##// END OF EJS Templates
Replacing some .items() calls with .iteritems() for cleaner conversion with 2to3.
Thomas Kluyver -
Show More
@@ -1,54 +1,54 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 IPython.
4 IPython.
5
5
6 IPython is a set of tools for interactive and exploratory computing in Python.
6 IPython is a set of tools for interactive and exploratory computing in Python.
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2009 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 from __future__ import absolute_import
18 from __future__ import absolute_import
19
19
20 import os
20 import os
21 import sys
21 import sys
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Setup everything
24 # Setup everything
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 if sys.version[0:3] < '2.6':
27 if sys.version[0:3] < '2.6':
28 raise ImportError('Python Version 2.6 or above is required for IPython.')
28 raise ImportError('Python Version 2.6 or above is required for IPython.')
29
29
30
30
31 # Make it easy to import extensions - they are always directly on pythonpath.
31 # Make it easy to import extensions - they are always directly on pythonpath.
32 # Therefore, non-IPython modules can be added to extensions directory.
32 # Therefore, non-IPython modules can be added to extensions directory.
33 # This should probably be in ipapp.py.
33 # This should probably be in ipapp.py.
34 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
34 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Setup the top level names
37 # Setup the top level names
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 from .config.loader import Config
40 from .config.loader import Config
41 from .core import release
41 from .core import release
42 from .core.application import Application
42 from .core.application import Application
43 from .frontend.terminal.embed import embed
43 from .frontend.terminal.embed import embed
44 from .core.error import TryNext
44 from .core.error import TryNext
45 from .core.interactiveshell import InteractiveShell
45 from .core.interactiveshell import InteractiveShell
46 from .testing import test
46 from .testing import test
47
47
48 # Release data
48 # Release data
49 __author__ = ''
49 __author__ = ''
50 for author, email in release.authors.values():
50 for author, email in release.authors.itervalues():
51 __author__ += author + ' <' + email + '>\n'
51 __author__ += author + ' <' + email + '>\n'
52 __license__ = release.license
52 __license__ = release.license
53 __version__ = release.version
53 __version__ = release.version
54 __revision__ = release.revision
54 __revision__ = release.revision
@@ -1,139 +1,139 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A base class for objects that are configurable.
4 A base class for objects that are configurable.
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-2010 The IPython Development Team
13 # Copyright (C) 2008-2010 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 import datetime
24 import datetime
25 from weakref import WeakValueDictionary
25 from weakref import WeakValueDictionary
26
26
27 from IPython.utils.importstring import import_item
27 from IPython.utils.importstring import import_item
28 from loader import Config
28 from loader import Config
29 from IPython.utils.traitlets import HasTraits, Instance
29 from IPython.utils.traitlets import HasTraits, Instance
30
30
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Helper classes for Configurables
33 # Helper classes for Configurables
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36
36
37 class ConfigurableError(Exception):
37 class ConfigurableError(Exception):
38 pass
38 pass
39
39
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Configurable implementation
42 # Configurable implementation
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45
45
46 class Configurable(HasTraits):
46 class Configurable(HasTraits):
47
47
48 config = Instance(Config,(),{})
48 config = Instance(Config,(),{})
49 created = None
49 created = None
50
50
51 def __init__(self, **kwargs):
51 def __init__(self, **kwargs):
52 """Create a conigurable given a config config.
52 """Create a conigurable given a config config.
53
53
54 Parameters
54 Parameters
55 ----------
55 ----------
56 config : Config
56 config : Config
57 If this is empty, default values are used. If config is a
57 If this is empty, default values are used. If config is a
58 :class:`Config` instance, it will be used to configure the
58 :class:`Config` instance, it will be used to configure the
59 instance.
59 instance.
60
60
61 Notes
61 Notes
62 -----
62 -----
63 Subclasses of Configurable must call the :meth:`__init__` method of
63 Subclasses of Configurable must call the :meth:`__init__` method of
64 :class:`Configurable` *before* doing anything else and using
64 :class:`Configurable` *before* doing anything else and using
65 :func:`super`::
65 :func:`super`::
66
66
67 class MyConfigurable(Configurable):
67 class MyConfigurable(Configurable):
68 def __init__(self, config=None):
68 def __init__(self, config=None):
69 super(MyConfigurable, self).__init__(config)
69 super(MyConfigurable, self).__init__(config)
70 # Then any other code you need to finish initialization.
70 # Then any other code you need to finish initialization.
71
71
72 This ensures that instances will be configured properly.
72 This ensures that instances will be configured properly.
73 """
73 """
74 config = kwargs.pop('config', None)
74 config = kwargs.pop('config', None)
75 if config is not None:
75 if config is not None:
76 # We used to deepcopy, but for now we are trying to just save
76 # We used to deepcopy, but for now we are trying to just save
77 # by reference. This *could* have side effects as all components
77 # by reference. This *could* have side effects as all components
78 # will share config. In fact, I did find such a side effect in
78 # will share config. In fact, I did find such a side effect in
79 # _config_changed below. If a config attribute value was a mutable type
79 # _config_changed below. If a config attribute value was a mutable type
80 # all instances of a component were getting the same copy, effectively
80 # all instances of a component were getting the same copy, effectively
81 # making that a class attribute.
81 # making that a class attribute.
82 # self.config = deepcopy(config)
82 # self.config = deepcopy(config)
83 self.config = config
83 self.config = config
84 # This should go second so individual keyword arguments override
84 # This should go second so individual keyword arguments override
85 # the values in config.
85 # the values in config.
86 super(Configurable, self).__init__(**kwargs)
86 super(Configurable, self).__init__(**kwargs)
87 self.created = datetime.datetime.now()
87 self.created = datetime.datetime.now()
88
88
89 #-------------------------------------------------------------------------
89 #-------------------------------------------------------------------------
90 # Static trait notifiations
90 # Static trait notifiations
91 #-------------------------------------------------------------------------
91 #-------------------------------------------------------------------------
92
92
93 def _config_changed(self, name, old, new):
93 def _config_changed(self, name, old, new):
94 """Update all the class traits having ``config=True`` as metadata.
94 """Update all the class traits having ``config=True`` as metadata.
95
95
96 For any class trait with a ``config`` metadata attribute that is
96 For any class trait with a ``config`` metadata attribute that is
97 ``True``, we update the trait with the value of the corresponding
97 ``True``, we update the trait with the value of the corresponding
98 config entry.
98 config entry.
99 """
99 """
100 # Get all traits with a config metadata entry that is True
100 # Get all traits with a config metadata entry that is True
101 traits = self.traits(config=True)
101 traits = self.traits(config=True)
102
102
103 # We auto-load config section for this class as well as any parent
103 # We auto-load config section for this class as well as any parent
104 # classes that are Configurable subclasses. This starts with Configurable
104 # classes that are Configurable subclasses. This starts with Configurable
105 # and works down the mro loading the config for each section.
105 # and works down the mro loading the config for each section.
106 section_names = [cls.__name__ for cls in \
106 section_names = [cls.__name__ for cls in \
107 reversed(self.__class__.__mro__) if
107 reversed(self.__class__.__mro__) if
108 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
108 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
109
109
110 for sname in section_names:
110 for sname in section_names:
111 # Don't do a blind getattr as that would cause the config to
111 # Don't do a blind getattr as that would cause the config to
112 # dynamically create the section with name self.__class__.__name__.
112 # dynamically create the section with name self.__class__.__name__.
113 if new._has_section(sname):
113 if new._has_section(sname):
114 my_config = new[sname]
114 my_config = new[sname]
115 for k, v in traits.items():
115 for k, v in traits.iteritems():
116 # Don't allow traitlets with config=True to start with
116 # Don't allow traitlets with config=True to start with
117 # uppercase. Otherwise, they are confused with Config
117 # uppercase. Otherwise, they are confused with Config
118 # subsections. But, developers shouldn't have uppercase
118 # subsections. But, developers shouldn't have uppercase
119 # attributes anyways! (PEP 6)
119 # attributes anyways! (PEP 6)
120 if k[0].upper()==k[0] and not k.startswith('_'):
120 if k[0].upper()==k[0] and not k.startswith('_'):
121 raise ConfigurableError('Configurable traitlets with '
121 raise ConfigurableError('Configurable traitlets with '
122 'config=True must start with a lowercase so they are '
122 'config=True must start with a lowercase so they are '
123 'not confused with Config subsections: %s.%s' % \
123 'not confused with Config subsections: %s.%s' % \
124 (self.__class__.__name__, k))
124 (self.__class__.__name__, k))
125 try:
125 try:
126 # Here we grab the value from the config
126 # Here we grab the value from the config
127 # If k has the naming convention of a config
127 # If k has the naming convention of a config
128 # section, it will be auto created.
128 # section, it will be auto created.
129 config_value = my_config[k]
129 config_value = my_config[k]
130 except KeyError:
130 except KeyError:
131 pass
131 pass
132 else:
132 else:
133 # print "Setting %s.%s from %s.%s=%r" % \
133 # print "Setting %s.%s from %s.%s=%r" % \
134 # (self.__class__.__name__,k,sname,k,config_value)
134 # (self.__class__.__name__,k,sname,k,config_value)
135 # We have to do a deepcopy here if we don't deepcopy the entire
135 # We have to do a deepcopy here if we don't deepcopy the entire
136 # config object. If we don't, a mutable config_value will be
136 # config object. If we don't, a mutable config_value will be
137 # shared by all instances, effectively making it a class attribute.
137 # shared by all instances, effectively making it a class attribute.
138 setattr(self, k, deepcopy(config_value))
138 setattr(self, k, deepcopy(config_value))
139
139
@@ -1,372 +1,373 b''
1 # -*- coding: utf-8 -*-
1 # coding: utf-8
2 # coding: utf-8
2 """A simple configuration system.
3 """A simple configuration system.
3
4
4 Authors
5 Authors
5 -------
6 -------
6 * Brian Granger
7 * Brian Granger
7 * Fernando Perez
8 * Fernando Perez
8 """
9 """
9
10
10 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2009 The IPython Development Team
12 # Copyright (C) 2008-2009 The IPython Development Team
12 #
13 #
13 # 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
14 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
16
17
17 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
18 # Imports
19 # Imports
19 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
20
21
21 import __builtin__
22 import __builtin__
22 import os
23 import os
23 import sys
24 import sys
24
25
25 from IPython.external import argparse
26 from IPython.external import argparse
26 from IPython.utils.path import filefind
27 from IPython.utils.path import filefind
27
28
28 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
29 # Exceptions
30 # Exceptions
30 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
31
32
32
33
33 class ConfigError(Exception):
34 class ConfigError(Exception):
34 pass
35 pass
35
36
36
37
37 class ConfigLoaderError(ConfigError):
38 class ConfigLoaderError(ConfigError):
38 pass
39 pass
39
40
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41 # Argparse fix
42 # Argparse fix
42 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
43
44
44 # Unfortunately argparse by default prints help messages to stderr instead of
45 # Unfortunately argparse by default prints help messages to stderr instead of
45 # stdout. This makes it annoying to capture long help screens at the command
46 # stdout. This makes it annoying to capture long help screens at the command
46 # line, since one must know how to pipe stderr, which many users don't know how
47 # line, since one must know how to pipe stderr, which many users don't know how
47 # to do. So we override the print_help method with one that defaults to
48 # to do. So we override the print_help method with one that defaults to
48 # stdout and use our class instead.
49 # stdout and use our class instead.
49
50
50 class ArgumentParser(argparse.ArgumentParser):
51 class ArgumentParser(argparse.ArgumentParser):
51 """Simple argparse subclass that prints help to stdout by default."""
52 """Simple argparse subclass that prints help to stdout by default."""
52
53
53 def print_help(self, file=None):
54 def print_help(self, file=None):
54 if file is None:
55 if file is None:
55 file = sys.stdout
56 file = sys.stdout
56 return super(ArgumentParser, self).print_help(file)
57 return super(ArgumentParser, self).print_help(file)
57
58
58 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
59 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
59
60
60 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
61 # Config class for holding config information
62 # Config class for holding config information
62 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
63
64
64
65
65 class Config(dict):
66 class Config(dict):
66 """An attribute based dict that can do smart merges."""
67 """An attribute based dict that can do smart merges."""
67
68
68 def __init__(self, *args, **kwds):
69 def __init__(self, *args, **kwds):
69 dict.__init__(self, *args, **kwds)
70 dict.__init__(self, *args, **kwds)
70 # This sets self.__dict__ = self, but it has to be done this way
71 # This sets self.__dict__ = self, but it has to be done this way
71 # because we are also overriding __setattr__.
72 # because we are also overriding __setattr__.
72 dict.__setattr__(self, '__dict__', self)
73 dict.__setattr__(self, '__dict__', self)
73
74
74 def _merge(self, other):
75 def _merge(self, other):
75 to_update = {}
76 to_update = {}
76 for k, v in other.items():
77 for k, v in other.iteritems():
77 if not self.has_key(k):
78 if not self.has_key(k):
78 to_update[k] = v
79 to_update[k] = v
79 else: # I have this key
80 else: # I have this key
80 if isinstance(v, Config):
81 if isinstance(v, Config):
81 # Recursively merge common sub Configs
82 # Recursively merge common sub Configs
82 self[k]._merge(v)
83 self[k]._merge(v)
83 else:
84 else:
84 # Plain updates for non-Configs
85 # Plain updates for non-Configs
85 to_update[k] = v
86 to_update[k] = v
86
87
87 self.update(to_update)
88 self.update(to_update)
88
89
89 def _is_section_key(self, key):
90 def _is_section_key(self, key):
90 if key[0].upper()==key[0] and not key.startswith('_'):
91 if key[0].upper()==key[0] and not key.startswith('_'):
91 return True
92 return True
92 else:
93 else:
93 return False
94 return False
94
95
95 def __contains__(self, key):
96 def __contains__(self, key):
96 if self._is_section_key(key):
97 if self._is_section_key(key):
97 return True
98 return True
98 else:
99 else:
99 return super(Config, self).__contains__(key)
100 return super(Config, self).__contains__(key)
100 # .has_key is deprecated for dictionaries.
101 # .has_key is deprecated for dictionaries.
101 has_key = __contains__
102 has_key = __contains__
102
103
103 def _has_section(self, key):
104 def _has_section(self, key):
104 if self._is_section_key(key):
105 if self._is_section_key(key):
105 if super(Config, self).__contains__(key):
106 if super(Config, self).__contains__(key):
106 return True
107 return True
107 return False
108 return False
108
109
109 def copy(self):
110 def copy(self):
110 return type(self)(dict.copy(self))
111 return type(self)(dict.copy(self))
111
112
112 def __copy__(self):
113 def __copy__(self):
113 return self.copy()
114 return self.copy()
114
115
115 def __deepcopy__(self, memo):
116 def __deepcopy__(self, memo):
116 import copy
117 import copy
117 return type(self)(copy.deepcopy(self.items()))
118 return type(self)(copy.deepcopy(self.items()))
118
119
119 def __getitem__(self, key):
120 def __getitem__(self, key):
120 # Because we use this for an exec namespace, we need to delegate
121 # Because we use this for an exec namespace, we need to delegate
121 # the lookup of names in __builtin__ to itself. This means
122 # the lookup of names in __builtin__ to itself. This means
122 # that you can't have section or attribute names that are
123 # that you can't have section or attribute names that are
123 # builtins.
124 # builtins.
124 try:
125 try:
125 return getattr(__builtin__, key)
126 return getattr(__builtin__, key)
126 except AttributeError:
127 except AttributeError:
127 pass
128 pass
128 if self._is_section_key(key):
129 if self._is_section_key(key):
129 try:
130 try:
130 return dict.__getitem__(self, key)
131 return dict.__getitem__(self, key)
131 except KeyError:
132 except KeyError:
132 c = Config()
133 c = Config()
133 dict.__setitem__(self, key, c)
134 dict.__setitem__(self, key, c)
134 return c
135 return c
135 else:
136 else:
136 return dict.__getitem__(self, key)
137 return dict.__getitem__(self, key)
137
138
138 def __setitem__(self, key, value):
139 def __setitem__(self, key, value):
139 # Don't allow names in __builtin__ to be modified.
140 # Don't allow names in __builtin__ to be modified.
140 if hasattr(__builtin__, key):
141 if hasattr(__builtin__, key):
141 raise ConfigError('Config variable names cannot have the same name '
142 raise ConfigError('Config variable names cannot have the same name '
142 'as a Python builtin: %s' % key)
143 'as a Python builtin: %s' % key)
143 if self._is_section_key(key):
144 if self._is_section_key(key):
144 if not isinstance(value, Config):
145 if not isinstance(value, Config):
145 raise ValueError('values whose keys begin with an uppercase '
146 raise ValueError('values whose keys begin with an uppercase '
146 'char must be Config instances: %r, %r' % (key, value))
147 'char must be Config instances: %r, %r' % (key, value))
147 else:
148 else:
148 dict.__setitem__(self, key, value)
149 dict.__setitem__(self, key, value)
149
150
150 def __getattr__(self, key):
151 def __getattr__(self, key):
151 try:
152 try:
152 return self.__getitem__(key)
153 return self.__getitem__(key)
153 except KeyError, e:
154 except KeyError, e:
154 raise AttributeError(e)
155 raise AttributeError(e)
155
156
156 def __setattr__(self, key, value):
157 def __setattr__(self, key, value):
157 try:
158 try:
158 self.__setitem__(key, value)
159 self.__setitem__(key, value)
159 except KeyError, e:
160 except KeyError, e:
160 raise AttributeError(e)
161 raise AttributeError(e)
161
162
162 def __delattr__(self, key):
163 def __delattr__(self, key):
163 try:
164 try:
164 dict.__delitem__(self, key)
165 dict.__delitem__(self, key)
165 except KeyError, e:
166 except KeyError, e:
166 raise AttributeError(e)
167 raise AttributeError(e)
167
168
168
169
169 #-----------------------------------------------------------------------------
170 #-----------------------------------------------------------------------------
170 # Config loading classes
171 # Config loading classes
171 #-----------------------------------------------------------------------------
172 #-----------------------------------------------------------------------------
172
173
173
174
174 class ConfigLoader(object):
175 class ConfigLoader(object):
175 """A object for loading configurations from just about anywhere.
176 """A object for loading configurations from just about anywhere.
176
177
177 The resulting configuration is packaged as a :class:`Struct`.
178 The resulting configuration is packaged as a :class:`Struct`.
178
179
179 Notes
180 Notes
180 -----
181 -----
181 A :class:`ConfigLoader` does one thing: load a config from a source
182 A :class:`ConfigLoader` does one thing: load a config from a source
182 (file, command line arguments) and returns the data as a :class:`Struct`.
183 (file, command line arguments) and returns the data as a :class:`Struct`.
183 There are lots of things that :class:`ConfigLoader` does not do. It does
184 There are lots of things that :class:`ConfigLoader` does not do. It does
184 not implement complex logic for finding config files. It does not handle
185 not implement complex logic for finding config files. It does not handle
185 default values or merge multiple configs. These things need to be
186 default values or merge multiple configs. These things need to be
186 handled elsewhere.
187 handled elsewhere.
187 """
188 """
188
189
189 def __init__(self):
190 def __init__(self):
190 """A base class for config loaders.
191 """A base class for config loaders.
191
192
192 Examples
193 Examples
193 --------
194 --------
194
195
195 >>> cl = ConfigLoader()
196 >>> cl = ConfigLoader()
196 >>> config = cl.load_config()
197 >>> config = cl.load_config()
197 >>> config
198 >>> config
198 {}
199 {}
199 """
200 """
200 self.clear()
201 self.clear()
201
202
202 def clear(self):
203 def clear(self):
203 self.config = Config()
204 self.config = Config()
204
205
205 def load_config(self):
206 def load_config(self):
206 """Load a config from somewhere, return a :class:`Config` instance.
207 """Load a config from somewhere, return a :class:`Config` instance.
207
208
208 Usually, this will cause self.config to be set and then returned.
209 Usually, this will cause self.config to be set and then returned.
209 However, in most cases, :meth:`ConfigLoader.clear` should be called
210 However, in most cases, :meth:`ConfigLoader.clear` should be called
210 to erase any previous state.
211 to erase any previous state.
211 """
212 """
212 self.clear()
213 self.clear()
213 return self.config
214 return self.config
214
215
215
216
216 class FileConfigLoader(ConfigLoader):
217 class FileConfigLoader(ConfigLoader):
217 """A base class for file based configurations.
218 """A base class for file based configurations.
218
219
219 As we add more file based config loaders, the common logic should go
220 As we add more file based config loaders, the common logic should go
220 here.
221 here.
221 """
222 """
222 pass
223 pass
223
224
224
225
225 class PyFileConfigLoader(FileConfigLoader):
226 class PyFileConfigLoader(FileConfigLoader):
226 """A config loader for pure python files.
227 """A config loader for pure python files.
227
228
228 This calls execfile on a plain python file and looks for attributes
229 This calls execfile on a plain python file and looks for attributes
229 that are all caps. These attribute are added to the config Struct.
230 that are all caps. These attribute are added to the config Struct.
230 """
231 """
231
232
232 def __init__(self, filename, path=None):
233 def __init__(self, filename, path=None):
233 """Build a config loader for a filename and path.
234 """Build a config loader for a filename and path.
234
235
235 Parameters
236 Parameters
236 ----------
237 ----------
237 filename : str
238 filename : str
238 The file name of the config file.
239 The file name of the config file.
239 path : str, list, tuple
240 path : str, list, tuple
240 The path to search for the config file on, or a sequence of
241 The path to search for the config file on, or a sequence of
241 paths to try in order.
242 paths to try in order.
242 """
243 """
243 super(PyFileConfigLoader, self).__init__()
244 super(PyFileConfigLoader, self).__init__()
244 self.filename = filename
245 self.filename = filename
245 self.path = path
246 self.path = path
246 self.full_filename = ''
247 self.full_filename = ''
247 self.data = None
248 self.data = None
248
249
249 def load_config(self):
250 def load_config(self):
250 """Load the config from a file and return it as a Struct."""
251 """Load the config from a file and return it as a Struct."""
251 self.clear()
252 self.clear()
252 self._find_file()
253 self._find_file()
253 self._read_file_as_dict()
254 self._read_file_as_dict()
254 self._convert_to_config()
255 self._convert_to_config()
255 return self.config
256 return self.config
256
257
257 def _find_file(self):
258 def _find_file(self):
258 """Try to find the file by searching the paths."""
259 """Try to find the file by searching the paths."""
259 self.full_filename = filefind(self.filename, self.path)
260 self.full_filename = filefind(self.filename, self.path)
260
261
261 def _read_file_as_dict(self):
262 def _read_file_as_dict(self):
262 """Load the config file into self.config, with recursive loading."""
263 """Load the config file into self.config, with recursive loading."""
263 # This closure is made available in the namespace that is used
264 # This closure is made available in the namespace that is used
264 # to exec the config file. This allows users to call
265 # to exec the config file. This allows users to call
265 # load_subconfig('myconfig.py') to load config files recursively.
266 # load_subconfig('myconfig.py') to load config files recursively.
266 # It needs to be a closure because it has references to self.path
267 # It needs to be a closure because it has references to self.path
267 # and self.config. The sub-config is loaded with the same path
268 # and self.config. The sub-config is loaded with the same path
268 # as the parent, but it uses an empty config which is then merged
269 # as the parent, but it uses an empty config which is then merged
269 # with the parents.
270 # with the parents.
270 def load_subconfig(fname):
271 def load_subconfig(fname):
271 loader = PyFileConfigLoader(fname, self.path)
272 loader = PyFileConfigLoader(fname, self.path)
272 try:
273 try:
273 sub_config = loader.load_config()
274 sub_config = loader.load_config()
274 except IOError:
275 except IOError:
275 # Pass silently if the sub config is not there. This happens
276 # Pass silently if the sub config is not there. This happens
276 # when a user us using a profile, but not the default config.
277 # when a user us using a profile, but not the default config.
277 pass
278 pass
278 else:
279 else:
279 self.config._merge(sub_config)
280 self.config._merge(sub_config)
280
281
281 # Again, this needs to be a closure and should be used in config
282 # Again, this needs to be a closure and should be used in config
282 # files to get the config being loaded.
283 # files to get the config being loaded.
283 def get_config():
284 def get_config():
284 return self.config
285 return self.config
285
286
286 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
287 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
287 execfile(self.full_filename, namespace)
288 execfile(self.full_filename, namespace)
288
289
289 def _convert_to_config(self):
290 def _convert_to_config(self):
290 if self.data is None:
291 if self.data is None:
291 ConfigLoaderError('self.data does not exist')
292 ConfigLoaderError('self.data does not exist')
292
293
293
294
294 class CommandLineConfigLoader(ConfigLoader):
295 class CommandLineConfigLoader(ConfigLoader):
295 """A config loader for command line arguments.
296 """A config loader for command line arguments.
296
297
297 As we add more command line based loaders, the common logic should go
298 As we add more command line based loaders, the common logic should go
298 here.
299 here.
299 """
300 """
300
301
301
302
302 class ArgParseConfigLoader(CommandLineConfigLoader):
303 class ArgParseConfigLoader(CommandLineConfigLoader):
303
304
304 def __init__(self, argv=None, *parser_args, **parser_kw):
305 def __init__(self, argv=None, *parser_args, **parser_kw):
305 """Create a config loader for use with argparse.
306 """Create a config loader for use with argparse.
306
307
307 Parameters
308 Parameters
308 ----------
309 ----------
309
310
310 argv : optional, list
311 argv : optional, list
311 If given, used to read command-line arguments from, otherwise
312 If given, used to read command-line arguments from, otherwise
312 sys.argv[1:] is used.
313 sys.argv[1:] is used.
313
314
314 parser_args : tuple
315 parser_args : tuple
315 A tuple of positional arguments that will be passed to the
316 A tuple of positional arguments that will be passed to the
316 constructor of :class:`argparse.ArgumentParser`.
317 constructor of :class:`argparse.ArgumentParser`.
317
318
318 parser_kw : dict
319 parser_kw : dict
319 A tuple of keyword arguments that will be passed to the
320 A tuple of keyword arguments that will be passed to the
320 constructor of :class:`argparse.ArgumentParser`.
321 constructor of :class:`argparse.ArgumentParser`.
321 """
322 """
322 super(CommandLineConfigLoader, self).__init__()
323 super(CommandLineConfigLoader, self).__init__()
323 if argv == None:
324 if argv == None:
324 argv = sys.argv[1:]
325 argv = sys.argv[1:]
325 self.argv = argv
326 self.argv = argv
326 self.parser_args = parser_args
327 self.parser_args = parser_args
327 kwargs = dict(argument_default=argparse.SUPPRESS)
328 kwargs = dict(argument_default=argparse.SUPPRESS)
328 kwargs.update(parser_kw)
329 kwargs.update(parser_kw)
329 self.parser_kw = kwargs
330 self.parser_kw = kwargs
330
331
331 def load_config(self, args=None):
332 def load_config(self, args=None):
332 """Parse command line arguments and return as a Struct.
333 """Parse command line arguments and return as a Struct.
333
334
334 Parameters
335 Parameters
335 ----------
336 ----------
336
337
337 args : optional, list
338 args : optional, list
338 If given, a list with the structure of sys.argv[1:] to parse
339 If given, a list with the structure of sys.argv[1:] to parse
339 arguments from. If not given, the instance's self.argv attribute
340 arguments from. If not given, the instance's self.argv attribute
340 (given at construction time) is used."""
341 (given at construction time) is used."""
341 self.clear()
342 self.clear()
342 if args is None:
343 if args is None:
343 args = self.argv
344 args = self.argv
344 self._create_parser()
345 self._create_parser()
345 self._parse_args(args)
346 self._parse_args(args)
346 self._convert_to_config()
347 self._convert_to_config()
347 return self.config
348 return self.config
348
349
349 def get_extra_args(self):
350 def get_extra_args(self):
350 if hasattr(self, 'extra_args'):
351 if hasattr(self, 'extra_args'):
351 return self.extra_args
352 return self.extra_args
352 else:
353 else:
353 return []
354 return []
354
355
355 def _create_parser(self):
356 def _create_parser(self):
356 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
357 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
357 self._add_arguments()
358 self._add_arguments()
358
359
359 def _add_arguments(self):
360 def _add_arguments(self):
360 raise NotImplementedError("subclasses must implement _add_arguments")
361 raise NotImplementedError("subclasses must implement _add_arguments")
361
362
362 def _parse_args(self, args):
363 def _parse_args(self, args):
363 """self.parser->self.parsed_data"""
364 """self.parser->self.parsed_data"""
364 self.parsed_data, self.extra_args = self.parser.parse_known_args(args)
365 self.parsed_data, self.extra_args = self.parser.parse_known_args(args)
365
366
366 def _convert_to_config(self):
367 def _convert_to_config(self):
367 """self.parsed_data->self.config"""
368 """self.parsed_data->self.config"""
368 for k, v in vars(self.parsed_data).items():
369 for k, v in vars(self.parsed_data).iteritems():
369 exec_str = 'self.config.' + k + '= v'
370 exec_str = 'self.config.' + k + '= v'
370 exec exec_str in locals(), globals()
371 exec exec_str in locals(), globals()
371
372
372
373
@@ -1,346 +1,346 b''
1 """Implementations for various useful completers.
1 """Implementations for various useful completers.
2
2
3 These are all loaded by default by IPython.
3 These are all loaded by default by IPython.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2010 The IPython Development Team.
6 # Copyright (C) 2010 The IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the BSD License.
8 # Distributed under the terms of the BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib imports
18 # Stdlib imports
19 import glob
19 import glob
20 import inspect
20 import inspect
21 import os
21 import os
22 import re
22 import re
23 import shlex
23 import shlex
24 import sys
24 import sys
25
25
26 # Third-party imports
26 # Third-party imports
27 from time import time
27 from time import time
28 from zipimport import zipimporter
28 from zipimport import zipimporter
29
29
30 # Our own imports
30 # Our own imports
31 from IPython.core.completer import expand_user, compress_user
31 from IPython.core.completer import expand_user, compress_user
32 from IPython.core.error import TryNext
32 from IPython.core.error import TryNext
33
33
34 # FIXME: this should be pulled in with the right call via the component system
34 # FIXME: this should be pulled in with the right call via the component system
35 from IPython.core.ipapi import get as get_ipython
35 from IPython.core.ipapi import get as get_ipython
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Globals and constants
38 # Globals and constants
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 # Time in seconds after which the rootmodules will be stored permanently in the
41 # Time in seconds after which the rootmodules will be stored permanently in the
42 # ipython ip.db database (kept in the user's .ipython dir).
42 # ipython ip.db database (kept in the user's .ipython dir).
43 TIMEOUT_STORAGE = 2
43 TIMEOUT_STORAGE = 2
44
44
45 # Time in seconds after which we give up
45 # Time in seconds after which we give up
46 TIMEOUT_GIVEUP = 20
46 TIMEOUT_GIVEUP = 20
47
47
48 # Regular expression for the python import statement
48 # Regular expression for the python import statement
49 import_re = re.compile(r'.*(\.so|\.py[cod]?)$')
49 import_re = re.compile(r'.*(\.so|\.py[cod]?)$')
50
50
51 # RE for the ipython %run command (python + ipython scripts)
51 # RE for the ipython %run command (python + ipython scripts)
52 magic_run_re = re.compile(r'.*(\.ipy|\.py[w]?)$')
52 magic_run_re = re.compile(r'.*(\.ipy|\.py[w]?)$')
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Local utilities
55 # Local utilities
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58 def shlex_split(x):
58 def shlex_split(x):
59 """Helper function to split lines into segments.
59 """Helper function to split lines into segments.
60 """
60 """
61 # shlex.split raises an exception if there is a syntax error in sh syntax
61 # shlex.split raises an exception if there is a syntax error in sh syntax
62 # for example if no closing " is found. This function keeps dropping the
62 # for example if no closing " is found. This function keeps dropping the
63 # last character of the line until shlex.split does not raise
63 # last character of the line until shlex.split does not raise
64 # an exception. It adds end of the line to the result of shlex.split
64 # an exception. It adds end of the line to the result of shlex.split
65 #
65 #
66 # Example:
66 # Example:
67 # %run "c:/python -> ['%run','"c:/python']
67 # %run "c:/python -> ['%run','"c:/python']
68
68
69 # shlex.split has unicode bugs, so encode first to str
69 # shlex.split has unicode bugs, so encode first to str
70 if isinstance(x, unicode):
70 if isinstance(x, unicode):
71 x = x.encode(sys.stdin.encoding)
71 x = x.encode(sys.stdin.encoding)
72
72
73 endofline = []
73 endofline = []
74 while x != '':
74 while x != '':
75 try:
75 try:
76 comps = shlex.split(x)
76 comps = shlex.split(x)
77 if len(endofline) >= 1:
77 if len(endofline) >= 1:
78 comps.append(''.join(endofline))
78 comps.append(''.join(endofline))
79 return comps
79 return comps
80
80
81 except ValueError:
81 except ValueError:
82 endofline = [x[-1:]]+endofline
82 endofline = [x[-1:]]+endofline
83 x = x[:-1]
83 x = x[:-1]
84
84
85 return [''.join(endofline)]
85 return [''.join(endofline)]
86
86
87 def module_list(path):
87 def module_list(path):
88 """
88 """
89 Return the list containing the names of the modules available in the given
89 Return the list containing the names of the modules available in the given
90 folder.
90 folder.
91 """
91 """
92
92
93 if os.path.isdir(path):
93 if os.path.isdir(path):
94 folder_list = os.listdir(path)
94 folder_list = os.listdir(path)
95 elif path.endswith('.egg'):
95 elif path.endswith('.egg'):
96 try:
96 try:
97 folder_list = [f for f in zipimporter(path)._files]
97 folder_list = [f for f in zipimporter(path)._files]
98 except:
98 except:
99 folder_list = []
99 folder_list = []
100 else:
100 else:
101 folder_list = []
101 folder_list = []
102
102
103 if not folder_list:
103 if not folder_list:
104 return []
104 return []
105
105
106 # A few local constants to be used in loops below
106 # A few local constants to be used in loops below
107 isfile = os.path.isfile
107 isfile = os.path.isfile
108 pjoin = os.path.join
108 pjoin = os.path.join
109 basename = os.path.basename
109 basename = os.path.basename
110
110
111 # Now find actual path matches for packages or modules
111 # Now find actual path matches for packages or modules
112 folder_list = [p for p in folder_list
112 folder_list = [p for p in folder_list
113 if isfile(pjoin(path, p,'__init__.py'))
113 if isfile(pjoin(path, p,'__init__.py'))
114 or import_re.match(p) ]
114 or import_re.match(p) ]
115
115
116 return [basename(p).split('.')[0] for p in folder_list]
116 return [basename(p).split('.')[0] for p in folder_list]
117
117
118 def get_root_modules():
118 def get_root_modules():
119 """
119 """
120 Returns a list containing the names of all the modules available in the
120 Returns a list containing the names of all the modules available in the
121 folders of the pythonpath.
121 folders of the pythonpath.
122 """
122 """
123 ip = get_ipython()
123 ip = get_ipython()
124
124
125 if 'rootmodules' in ip.db:
125 if 'rootmodules' in ip.db:
126 return ip.db['rootmodules']
126 return ip.db['rootmodules']
127
127
128 t = time()
128 t = time()
129 store = False
129 store = False
130 modules = list(sys.builtin_module_names)
130 modules = list(sys.builtin_module_names)
131 for path in sys.path:
131 for path in sys.path:
132 modules += module_list(path)
132 modules += module_list(path)
133 if time() - t >= TIMEOUT_STORAGE and not store:
133 if time() - t >= TIMEOUT_STORAGE and not store:
134 store = True
134 store = True
135 print("\nCaching the list of root modules, please wait!")
135 print("\nCaching the list of root modules, please wait!")
136 print("(This will only be done once - type '%rehashx' to "
136 print("(This will only be done once - type '%rehashx' to "
137 "reset cache!)\n")
137 "reset cache!)\n")
138 sys.stdout.flush()
138 sys.stdout.flush()
139 if time() - t > TIMEOUT_GIVEUP:
139 if time() - t > TIMEOUT_GIVEUP:
140 print("This is taking too long, we give up.\n")
140 print("This is taking too long, we give up.\n")
141 ip.db['rootmodules'] = []
141 ip.db['rootmodules'] = []
142 return []
142 return []
143
143
144 modules = set(modules)
144 modules = set(modules)
145 if '__init__' in modules:
145 if '__init__' in modules:
146 modules.remove('__init__')
146 modules.remove('__init__')
147 modules = list(modules)
147 modules = list(modules)
148 if store:
148 if store:
149 ip.db['rootmodules'] = modules
149 ip.db['rootmodules'] = modules
150 return modules
150 return modules
151
151
152
152
153 def is_importable(module, attr, only_modules):
153 def is_importable(module, attr, only_modules):
154 if only_modules:
154 if only_modules:
155 return inspect.ismodule(getattr(module, attr))
155 return inspect.ismodule(getattr(module, attr))
156 else:
156 else:
157 return not(attr[:2] == '__' and attr[-2:] == '__')
157 return not(attr[:2] == '__' and attr[-2:] == '__')
158
158
159
159
160 def try_import(mod, only_modules=False):
160 def try_import(mod, only_modules=False):
161 try:
161 try:
162 m = __import__(mod)
162 m = __import__(mod)
163 except:
163 except:
164 return []
164 return []
165 mods = mod.split('.')
165 mods = mod.split('.')
166 for module in mods[1:]:
166 for module in mods[1:]:
167 m = getattr(m, module)
167 m = getattr(m, module)
168
168
169 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
169 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
170
170
171 completions = []
171 completions = []
172 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
172 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
173 completions.extend( [attr for attr in dir(m) if
173 completions.extend( [attr for attr in dir(m) if
174 is_importable(m, attr, only_modules)])
174 is_importable(m, attr, only_modules)])
175
175
176 completions.extend(getattr(m, '__all__', []))
176 completions.extend(getattr(m, '__all__', []))
177 if m_is_init:
177 if m_is_init:
178 completions.extend(module_list(os.path.dirname(m.__file__)))
178 completions.extend(module_list(os.path.dirname(m.__file__)))
179 completions = set(completions)
179 completions = set(completions)
180 if '__init__' in completions:
180 if '__init__' in completions:
181 completions.remove('__init__')
181 completions.remove('__init__')
182 return list(completions)
182 return list(completions)
183
183
184
184
185 #-----------------------------------------------------------------------------
185 #-----------------------------------------------------------------------------
186 # Completion-related functions.
186 # Completion-related functions.
187 #-----------------------------------------------------------------------------
187 #-----------------------------------------------------------------------------
188
188
189 def quick_completer(cmd, completions):
189 def quick_completer(cmd, completions):
190 """ Easily create a trivial completer for a command.
190 """ Easily create a trivial completer for a command.
191
191
192 Takes either a list of completions, or all completions in string (that will
192 Takes either a list of completions, or all completions in string (that will
193 be split on whitespace).
193 be split on whitespace).
194
194
195 Example::
195 Example::
196
196
197 [d:\ipython]|1> import ipy_completers
197 [d:\ipython]|1> import ipy_completers
198 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
198 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
199 [d:\ipython]|3> foo b<TAB>
199 [d:\ipython]|3> foo b<TAB>
200 bar baz
200 bar baz
201 [d:\ipython]|3> foo ba
201 [d:\ipython]|3> foo ba
202 """
202 """
203
203
204 if isinstance(completions, basestring):
204 if isinstance(completions, basestring):
205 completions = completions.split()
205 completions = completions.split()
206
206
207 def do_complete(self, event):
207 def do_complete(self, event):
208 return completions
208 return completions
209
209
210 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
210 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
211
211
212
212
213 def module_completion(line):
213 def module_completion(line):
214 """
214 """
215 Returns a list containing the completion possibilities for an import line.
215 Returns a list containing the completion possibilities for an import line.
216
216
217 The line looks like this :
217 The line looks like this :
218 'import xml.d'
218 'import xml.d'
219 'from xml.dom import'
219 'from xml.dom import'
220 """
220 """
221
221
222 words = line.split(' ')
222 words = line.split(' ')
223 nwords = len(words)
223 nwords = len(words)
224
224
225 # from whatever <tab> -> 'import '
225 # from whatever <tab> -> 'import '
226 if nwords == 3 and words[0] == 'from':
226 if nwords == 3 and words[0] == 'from':
227 return ['import ']
227 return ['import ']
228
228
229 # 'from xy<tab>' or 'import xy<tab>'
229 # 'from xy<tab>' or 'import xy<tab>'
230 if nwords < 3 and (words[0] in ['import','from']) :
230 if nwords < 3 and (words[0] in ['import','from']) :
231 if nwords == 1:
231 if nwords == 1:
232 return get_root_modules()
232 return get_root_modules()
233 mod = words[1].split('.')
233 mod = words[1].split('.')
234 if len(mod) < 2:
234 if len(mod) < 2:
235 return get_root_modules()
235 return get_root_modules()
236 completion_list = try_import('.'.join(mod[:-1]), True)
236 completion_list = try_import('.'.join(mod[:-1]), True)
237 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
237 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
238
238
239 # 'from xyz import abc<tab>'
239 # 'from xyz import abc<tab>'
240 if nwords >= 3 and words[0] == 'from':
240 if nwords >= 3 and words[0] == 'from':
241 mod = words[1]
241 mod = words[1]
242 return try_import(mod)
242 return try_import(mod)
243
243
244 #-----------------------------------------------------------------------------
244 #-----------------------------------------------------------------------------
245 # Completers
245 # Completers
246 #-----------------------------------------------------------------------------
246 #-----------------------------------------------------------------------------
247 # These all have the func(self, event) signature to be used as custom
247 # These all have the func(self, event) signature to be used as custom
248 # completers
248 # completers
249
249
250 def module_completer(self,event):
250 def module_completer(self,event):
251 """Give completions after user has typed 'import ...' or 'from ...'"""
251 """Give completions after user has typed 'import ...' or 'from ...'"""
252
252
253 # This works in all versions of python. While 2.5 has
253 # This works in all versions of python. While 2.5 has
254 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
254 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
255 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
255 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
256 # of possibly problematic side effects.
256 # of possibly problematic side effects.
257 # This search the folders in the sys.path for available modules.
257 # This search the folders in the sys.path for available modules.
258
258
259 return module_completion(event.line)
259 return module_completion(event.line)
260
260
261 # FIXME: there's a lot of logic common to the run, cd and builtin file
261 # FIXME: there's a lot of logic common to the run, cd and builtin file
262 # completers, that is currently reimplemented in each.
262 # completers, that is currently reimplemented in each.
263
263
264 def magic_run_completer(self, event):
264 def magic_run_completer(self, event):
265 """Complete files that end in .py or .ipy for the %run command.
265 """Complete files that end in .py or .ipy for the %run command.
266 """
266 """
267 comps = shlex_split(event.line)
267 comps = shlex_split(event.line)
268 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
268 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
269
269
270 #print("\nev=", event) # dbg
270 #print("\nev=", event) # dbg
271 #print("rp=", relpath) # dbg
271 #print("rp=", relpath) # dbg
272 #print('comps=', comps) # dbg
272 #print('comps=', comps) # dbg
273
273
274 lglob = glob.glob
274 lglob = glob.glob
275 isdir = os.path.isdir
275 isdir = os.path.isdir
276 relpath, tilde_expand, tilde_val = expand_user(relpath)
276 relpath, tilde_expand, tilde_val = expand_user(relpath)
277
277
278 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
278 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
279
279
280 # Find if the user has already typed the first filename, after which we
280 # Find if the user has already typed the first filename, after which we
281 # should complete on all files, since after the first one other files may
281 # should complete on all files, since after the first one other files may
282 # be arguments to the input script.
282 # be arguments to the input script.
283
283
284 if filter(magic_run_re.match, comps):
284 if filter(magic_run_re.match, comps):
285 pys = [f.replace('\\','/') for f in lglob('*')]
285 pys = [f.replace('\\','/') for f in lglob('*')]
286 else:
286 else:
287 pys = [f.replace('\\','/')
287 pys = [f.replace('\\','/')
288 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
288 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
289 lglob(relpath + '*.pyw')]
289 lglob(relpath + '*.pyw')]
290 #print('run comp:', dirs+pys) # dbg
290 #print('run comp:', dirs+pys) # dbg
291 return [compress_user(p, tilde_expand, tilde_val) for p in dirs+pys]
291 return [compress_user(p, tilde_expand, tilde_val) for p in dirs+pys]
292
292
293
293
294 def cd_completer(self, event):
294 def cd_completer(self, event):
295 """Completer function for cd, which only returns directories."""
295 """Completer function for cd, which only returns directories."""
296 ip = get_ipython()
296 ip = get_ipython()
297 relpath = event.symbol
297 relpath = event.symbol
298
298
299 #print(event) # dbg
299 #print(event) # dbg
300 if event.line.endswith('-b') or ' -b ' in event.line:
300 if event.line.endswith('-b') or ' -b ' in event.line:
301 # return only bookmark completions
301 # return only bookmark completions
302 bkms = self.db.get('bookmarks', None)
302 bkms = self.db.get('bookmarks', None)
303 if bkms:
303 if bkms:
304 return bkms.keys()
304 return bkms.keys()
305 else:
305 else:
306 return []
306 return []
307
307
308 if event.symbol == '-':
308 if event.symbol == '-':
309 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
309 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
310 # jump in directory history by number
310 # jump in directory history by number
311 fmt = '-%0' + width_dh +'d [%s]'
311 fmt = '-%0' + width_dh +'d [%s]'
312 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
312 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
313 if len(ents) > 1:
313 if len(ents) > 1:
314 return ents
314 return ents
315 return []
315 return []
316
316
317 if event.symbol.startswith('--'):
317 if event.symbol.startswith('--'):
318 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
318 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
319
319
320 # Expand ~ in path and normalize directory separators.
320 # Expand ~ in path and normalize directory separators.
321 relpath, tilde_expand, tilde_val = expand_user(relpath)
321 relpath, tilde_expand, tilde_val = expand_user(relpath)
322 relpath = relpath.replace('\\','/')
322 relpath = relpath.replace('\\','/')
323
323
324 found = []
324 found = []
325 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
325 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
326 if os.path.isdir(f)]:
326 if os.path.isdir(f)]:
327 if ' ' in d:
327 if ' ' in d:
328 # we don't want to deal with any of that, complex code
328 # we don't want to deal with any of that, complex code
329 # for this is elsewhere
329 # for this is elsewhere
330 raise TryNext
330 raise TryNext
331
331
332 found.append(d)
332 found.append(d)
333
333
334 if not found:
334 if not found:
335 if os.path.isdir(relpath):
335 if os.path.isdir(relpath):
336 return [compress_user(relpath, tilde_expand, tilde_val)]
336 return [compress_user(relpath, tilde_expand, tilde_val)]
337
337
338 # if no completions so far, try bookmarks
338 # if no completions so far, try bookmarks
339 bks = self.db.get('bookmarks',{}).keys()
339 bks = self.db.get('bookmarks',{}).iterkeys()
340 bkmatches = [s for s in bks if s.startswith(event.symbol)]
340 bkmatches = [s for s in bks if s.startswith(event.symbol)]
341 if bkmatches:
341 if bkmatches:
342 return bkmatches
342 return bkmatches
343
343
344 raise TryNext
344 raise TryNext
345
345
346 return [compress_user(p, tilde_expand, tilde_val) for p in found]
346 return [compress_user(p, tilde_expand, tilde_val) for p in found]
@@ -1,283 +1,283 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """ History related magics and functionality """
2 """ History related magics and functionality """
3
3
4 # Stdlib imports
4 # Stdlib imports
5 import fnmatch
5 import fnmatch
6 import os
6 import os
7
7
8 import IPython.utils.io
8 import IPython.utils.io
9 from IPython.utils.io import ask_yes_no
9 from IPython.utils.io import ask_yes_no
10 from IPython.utils.warn import warn
10 from IPython.utils.warn import warn
11 from IPython.core import ipapi
11 from IPython.core import ipapi
12
12
13 def magic_history(self, parameter_s = ''):
13 def magic_history(self, parameter_s = ''):
14 """Print input history (_i<n> variables), with most recent last.
14 """Print input history (_i<n> variables), with most recent last.
15
15
16 %history -> print at most 40 inputs (some may be multi-line)\\
16 %history -> print at most 40 inputs (some may be multi-line)\\
17 %history n -> print at most n inputs\\
17 %history n -> print at most n inputs\\
18 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
18 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
19
19
20 By default, input history is printed without line numbers so it can be
20 By default, input history is printed without line numbers so it can be
21 directly pasted into an editor.
21 directly pasted into an editor.
22
22
23 With -n, each input's number <n> is shown, and is accessible as the
23 With -n, each input's number <n> is shown, and is accessible as the
24 automatically generated variable _i<n> as well as In[<n>]. Multi-line
24 automatically generated variable _i<n> as well as In[<n>]. Multi-line
25 statements are printed starting at a new line for easy copy/paste.
25 statements are printed starting at a new line for easy copy/paste.
26
26
27 Options:
27 Options:
28
28
29 -n: print line numbers for each input.
29 -n: print line numbers for each input.
30 This feature is only available if numbered prompts are in use.
30 This feature is only available if numbered prompts are in use.
31
31
32 -o: also print outputs for each input.
32 -o: also print outputs for each input.
33
33
34 -p: print classic '>>>' python prompts before each input. This is useful
34 -p: print classic '>>>' python prompts before each input. This is useful
35 for making documentation, and in conjunction with -o, for producing
35 for making documentation, and in conjunction with -o, for producing
36 doctest-ready output.
36 doctest-ready output.
37
37
38 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
38 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
39
39
40 -t: print the 'translated' history, as IPython understands it. IPython
40 -t: print the 'translated' history, as IPython understands it. IPython
41 filters your input and converts it all into valid Python source before
41 filters your input and converts it all into valid Python source before
42 executing it (things like magics or aliases are turned into function
42 executing it (things like magics or aliases are turned into function
43 calls, for example). With this option, you'll see the native history
43 calls, for example). With this option, you'll see the native history
44 instead of the user-entered version: '%cd /' will be seen as
44 instead of the user-entered version: '%cd /' will be seen as
45 'get_ipython().magic("%cd /")' instead of '%cd /'.
45 'get_ipython().magic("%cd /")' instead of '%cd /'.
46
46
47 -g: treat the arg as a pattern to grep for in (full) history.
47 -g: treat the arg as a pattern to grep for in (full) history.
48 This includes the "shadow history" (almost all commands ever written).
48 This includes the "shadow history" (almost all commands ever written).
49 Use '%hist -g' to show full shadow history (may be very long).
49 Use '%hist -g' to show full shadow history (may be very long).
50 In shadow history, every index nuwber starts with 0.
50 In shadow history, every index nuwber starts with 0.
51
51
52 -f FILENAME: instead of printing the output to the screen, redirect it to
52 -f FILENAME: instead of printing the output to the screen, redirect it to
53 the given file. The file is always overwritten, though IPython asks for
53 the given file. The file is always overwritten, though IPython asks for
54 confirmation first if it already exists.
54 confirmation first if it already exists.
55 """
55 """
56
56
57 if not self.shell.displayhook.do_full_cache:
57 if not self.shell.displayhook.do_full_cache:
58 print 'This feature is only available if numbered prompts are in use.'
58 print 'This feature is only available if numbered prompts are in use.'
59 return
59 return
60 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
60 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
61
61
62 # Check if output to specific file was requested.
62 # Check if output to specific file was requested.
63 try:
63 try:
64 outfname = opts['f']
64 outfname = opts['f']
65 except KeyError:
65 except KeyError:
66 outfile = IPython.utils.io.Term.cout # default
66 outfile = IPython.utils.io.Term.cout # default
67 # We don't want to close stdout at the end!
67 # We don't want to close stdout at the end!
68 close_at_end = False
68 close_at_end = False
69 else:
69 else:
70 if os.path.exists(outfname):
70 if os.path.exists(outfname):
71 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
71 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
72 print 'Aborting.'
72 print 'Aborting.'
73 return
73 return
74
74
75 outfile = open(outfname,'w')
75 outfile = open(outfname,'w')
76 close_at_end = True
76 close_at_end = True
77
77
78 if 't' in opts:
78 if 't' in opts:
79 input_hist = self.shell.input_hist
79 input_hist = self.shell.input_hist
80 elif 'r' in opts:
80 elif 'r' in opts:
81 input_hist = self.shell.input_hist_raw
81 input_hist = self.shell.input_hist_raw
82 else:
82 else:
83 # Raw history is the default
83 # Raw history is the default
84 input_hist = self.shell.input_hist_raw
84 input_hist = self.shell.input_hist_raw
85
85
86 default_length = 40
86 default_length = 40
87 pattern = None
87 pattern = None
88 if 'g' in opts:
88 if 'g' in opts:
89 init = 1
89 init = 1
90 final = len(input_hist)
90 final = len(input_hist)
91 parts = parameter_s.split(None, 1)
91 parts = parameter_s.split(None, 1)
92 if len(parts) == 1:
92 if len(parts) == 1:
93 parts += '*'
93 parts += '*'
94 head, pattern = parts
94 head, pattern = parts
95 pattern = "*" + pattern + "*"
95 pattern = "*" + pattern + "*"
96 elif len(args) == 0:
96 elif len(args) == 0:
97 final = len(input_hist)-1
97 final = len(input_hist)-1
98 init = max(1,final-default_length)
98 init = max(1,final-default_length)
99 elif len(args) == 1:
99 elif len(args) == 1:
100 final = len(input_hist)
100 final = len(input_hist)
101 init = max(1, final-int(args[0]))
101 init = max(1, final-int(args[0]))
102 elif len(args) == 2:
102 elif len(args) == 2:
103 init, final = map(int, args)
103 init, final = map(int, args)
104 else:
104 else:
105 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
105 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
106 print >> IPython.utils.io.Term.cout, self.magic_hist.__doc__
106 print >> IPython.utils.io.Term.cout, self.magic_hist.__doc__
107 return
107 return
108
108
109 width = len(str(final))
109 width = len(str(final))
110 line_sep = ['','\n']
110 line_sep = ['','\n']
111 print_nums = 'n' in opts
111 print_nums = 'n' in opts
112 print_outputs = 'o' in opts
112 print_outputs = 'o' in opts
113 pyprompts = 'p' in opts
113 pyprompts = 'p' in opts
114
114
115 found = False
115 found = False
116 if pattern is not None:
116 if pattern is not None:
117 sh = self.shell.shadowhist.all()
117 sh = self.shell.shadowhist.all()
118 for idx, s in sh:
118 for idx, s in sh:
119 if fnmatch.fnmatch(s, pattern):
119 if fnmatch.fnmatch(s, pattern):
120 print >> outfile, "0%d: %s" %(idx, s.expandtabs(4))
120 print >> outfile, "0%d: %s" %(idx, s.expandtabs(4))
121 found = True
121 found = True
122
122
123 if found:
123 if found:
124 print >> outfile, "==="
124 print >> outfile, "==="
125 print >> outfile, \
125 print >> outfile, \
126 "shadow history ends, fetch by %rep <number> (must start with 0)"
126 "shadow history ends, fetch by %rep <number> (must start with 0)"
127 print >> outfile, "=== start of normal history ==="
127 print >> outfile, "=== start of normal history ==="
128
128
129 for in_num in range(init, final):
129 for in_num in range(init, final):
130 # Print user history with tabs expanded to 4 spaces. The GUI clients
130 # Print user history with tabs expanded to 4 spaces. The GUI clients
131 # use hard tabs for easier usability in auto-indented code, but we want
131 # use hard tabs for easier usability in auto-indented code, but we want
132 # to produce PEP-8 compliant history for safe pasting into an editor.
132 # to produce PEP-8 compliant history for safe pasting into an editor.
133 inline = input_hist[in_num].expandtabs(4)
133 inline = input_hist[in_num].expandtabs(4)
134
134
135 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
135 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
136 continue
136 continue
137
137
138 multiline = int(inline.count('\n') > 1)
138 multiline = int(inline.count('\n') > 1)
139 if print_nums:
139 if print_nums:
140 print >> outfile, \
140 print >> outfile, \
141 '%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
141 '%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
142 if pyprompts:
142 if pyprompts:
143 print >> outfile, '>>>',
143 print >> outfile, '>>>',
144 if multiline:
144 if multiline:
145 lines = inline.splitlines()
145 lines = inline.splitlines()
146 print >> outfile, '\n... '.join(lines)
146 print >> outfile, '\n... '.join(lines)
147 print >> outfile, '... '
147 print >> outfile, '... '
148 else:
148 else:
149 print >> outfile, inline,
149 print >> outfile, inline,
150 else:
150 else:
151 print >> outfile, inline,
151 print >> outfile, inline,
152 if print_outputs:
152 if print_outputs:
153 output = self.shell.output_hist.get(in_num)
153 output = self.shell.output_hist.get(in_num)
154 if output is not None:
154 if output is not None:
155 print >> outfile, repr(output)
155 print >> outfile, repr(output)
156
156
157 if close_at_end:
157 if close_at_end:
158 outfile.close()
158 outfile.close()
159
159
160
160
161 def magic_hist(self, parameter_s=''):
161 def magic_hist(self, parameter_s=''):
162 """Alternate name for %history."""
162 """Alternate name for %history."""
163 return self.magic_history(parameter_s)
163 return self.magic_history(parameter_s)
164
164
165
165
166 def rep_f(self, arg):
166 def rep_f(self, arg):
167 r""" Repeat a command, or get command to input line for editing
167 r""" Repeat a command, or get command to input line for editing
168
168
169 - %rep (no arguments):
169 - %rep (no arguments):
170
170
171 Place a string version of last computation result (stored in the special '_'
171 Place a string version of last computation result (stored in the special '_'
172 variable) to the next input prompt. Allows you to create elaborate command
172 variable) to the next input prompt. Allows you to create elaborate command
173 lines without using copy-paste::
173 lines without using copy-paste::
174
174
175 $ l = ["hei", "vaan"]
175 $ l = ["hei", "vaan"]
176 $ "".join(l)
176 $ "".join(l)
177 ==> heivaan
177 ==> heivaan
178 $ %rep
178 $ %rep
179 $ heivaan_ <== cursor blinking
179 $ heivaan_ <== cursor blinking
180
180
181 %rep 45
181 %rep 45
182
182
183 Place history line 45 to next input prompt. Use %hist to find out the
183 Place history line 45 to next input prompt. Use %hist to find out the
184 number.
184 number.
185
185
186 %rep 1-4 6-7 3
186 %rep 1-4 6-7 3
187
187
188 Repeat the specified lines immediately. Input slice syntax is the same as
188 Repeat the specified lines immediately. Input slice syntax is the same as
189 in %macro and %save.
189 in %macro and %save.
190
190
191 %rep foo
191 %rep foo
192
192
193 Place the most recent line that has the substring "foo" to next input.
193 Place the most recent line that has the substring "foo" to next input.
194 (e.g. 'svn ci -m foobar').
194 (e.g. 'svn ci -m foobar').
195 """
195 """
196
196
197 opts,args = self.parse_options(arg,'',mode='list')
197 opts,args = self.parse_options(arg,'',mode='list')
198 if not args:
198 if not args:
199 self.set_next_input(str(self.shell.user_ns["_"]))
199 self.set_next_input(str(self.shell.user_ns["_"]))
200 return
200 return
201
201
202 if len(args) == 1 and not '-' in args[0]:
202 if len(args) == 1 and not '-' in args[0]:
203 arg = args[0]
203 arg = args[0]
204 if len(arg) > 1 and arg.startswith('0'):
204 if len(arg) > 1 and arg.startswith('0'):
205 # get from shadow hist
205 # get from shadow hist
206 num = int(arg[1:])
206 num = int(arg[1:])
207 line = self.shell.shadowhist.get(num)
207 line = self.shell.shadowhist.get(num)
208 self.set_next_input(str(line))
208 self.set_next_input(str(line))
209 return
209 return
210 try:
210 try:
211 num = int(args[0])
211 num = int(args[0])
212 self.set_next_input(str(self.shell.input_hist_raw[num]).rstrip())
212 self.set_next_input(str(self.shell.input_hist_raw[num]).rstrip())
213 return
213 return
214 except ValueError:
214 except ValueError:
215 pass
215 pass
216
216
217 for h in reversed(self.shell.input_hist_raw):
217 for h in reversed(self.shell.input_hist_raw):
218 if 'rep' in h:
218 if 'rep' in h:
219 continue
219 continue
220 if fnmatch.fnmatch(h,'*' + arg + '*'):
220 if fnmatch.fnmatch(h,'*' + arg + '*'):
221 self.set_next_input(str(h).rstrip())
221 self.set_next_input(str(h).rstrip())
222 return
222 return
223
223
224 try:
224 try:
225 lines = self.extract_input_slices(args, True)
225 lines = self.extract_input_slices(args, True)
226 print "lines",lines
226 print "lines",lines
227 self.runlines(lines)
227 self.runlines(lines)
228 except ValueError:
228 except ValueError:
229 print "Not found in recent history:", args
229 print "Not found in recent history:", args
230
230
231
231
232 _sentinel = object()
232 _sentinel = object()
233
233
234 class ShadowHist(object):
234 class ShadowHist(object):
235 def __init__(self, db):
235 def __init__(self, db):
236 # cmd => idx mapping
236 # cmd => idx mapping
237 self.curidx = 0
237 self.curidx = 0
238 self.db = db
238 self.db = db
239 self.disabled = False
239 self.disabled = False
240
240
241 def inc_idx(self):
241 def inc_idx(self):
242 idx = self.db.get('shadowhist_idx', 1)
242 idx = self.db.get('shadowhist_idx', 1)
243 self.db['shadowhist_idx'] = idx + 1
243 self.db['shadowhist_idx'] = idx + 1
244 return idx
244 return idx
245
245
246 def add(self, ent):
246 def add(self, ent):
247 if self.disabled:
247 if self.disabled:
248 return
248 return
249 try:
249 try:
250 old = self.db.hget('shadowhist', ent, _sentinel)
250 old = self.db.hget('shadowhist', ent, _sentinel)
251 if old is not _sentinel:
251 if old is not _sentinel:
252 return
252 return
253 newidx = self.inc_idx()
253 newidx = self.inc_idx()
254 #print "new",newidx # dbg
254 #print "new",newidx # dbg
255 self.db.hset('shadowhist',ent, newidx)
255 self.db.hset('shadowhist',ent, newidx)
256 except:
256 except:
257 ipapi.get().showtraceback()
257 ipapi.get().showtraceback()
258 print "WARNING: disabling shadow history"
258 print "WARNING: disabling shadow history"
259 self.disabled = True
259 self.disabled = True
260
260
261 def all(self):
261 def all(self):
262 d = self.db.hdict('shadowhist')
262 d = self.db.hdict('shadowhist')
263 items = [(i,s) for (s,i) in d.items()]
263 items = [(i,s) for (s,i) in d.iteritems()]
264 items.sort()
264 items.sort()
265 return items
265 return items
266
266
267 def get(self, idx):
267 def get(self, idx):
268 all = self.all()
268 all = self.all()
269
269
270 for k, v in all:
270 for k, v in all:
271 #print k,v
271 #print k,v
272 if k == idx:
272 if k == idx:
273 return v
273 return v
274
274
275
275
276 def init_ipython(ip):
276 def init_ipython(ip):
277 ip.define_magic("rep",rep_f)
277 ip.define_magic("rep",rep_f)
278 ip.define_magic("hist",magic_hist)
278 ip.define_magic("hist",magic_hist)
279 ip.define_magic("history",magic_history)
279 ip.define_magic("history",magic_history)
280
280
281 # XXX - ipy_completers are in quarantine, need to be updated to new apis
281 # XXX - ipy_completers are in quarantine, need to be updated to new apis
282 #import ipy_completers
282 #import ipy_completers
283 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
283 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
@@ -1,2584 +1,2584 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2010 The IPython Development Team
7 # Copyright (C) 2008-2010 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import with_statement
17 from __future__ import with_statement
18 from __future__ import absolute_import
18 from __future__ import absolute_import
19
19
20 import __builtin__
20 import __builtin__
21 import __future__
21 import __future__
22 import abc
22 import abc
23 import atexit
23 import atexit
24 import codeop
24 import codeop
25 import os
25 import os
26 import re
26 import re
27 import string
27 import string
28 import sys
28 import sys
29 import tempfile
29 import tempfile
30 import types
30 import types
31 from contextlib import nested
31 from contextlib import nested
32
32
33 from IPython.config.configurable import Configurable
33 from IPython.config.configurable import Configurable
34 from IPython.core import debugger, oinspect
34 from IPython.core import debugger, oinspect
35 from IPython.core import history as ipcorehist
35 from IPython.core import history as ipcorehist
36 from IPython.core import page
36 from IPython.core import page
37 from IPython.core import prefilter
37 from IPython.core import prefilter
38 from IPython.core import shadowns
38 from IPython.core import shadowns
39 from IPython.core import ultratb
39 from IPython.core import ultratb
40 from IPython.core.alias import AliasManager
40 from IPython.core.alias import AliasManager
41 from IPython.core.builtin_trap import BuiltinTrap
41 from IPython.core.builtin_trap import BuiltinTrap
42 from IPython.core.display_trap import DisplayTrap
42 from IPython.core.display_trap import DisplayTrap
43 from IPython.core.displayhook import DisplayHook
43 from IPython.core.displayhook import DisplayHook
44 from IPython.core.error import TryNext, UsageError
44 from IPython.core.error import TryNext, UsageError
45 from IPython.core.extensions import ExtensionManager
45 from IPython.core.extensions import ExtensionManager
46 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
46 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
47 from IPython.core.inputlist import InputList
47 from IPython.core.inputlist import InputList
48 from IPython.core.inputsplitter import IPythonInputSplitter
48 from IPython.core.inputsplitter import IPythonInputSplitter
49 from IPython.core.logger import Logger
49 from IPython.core.logger import Logger
50 from IPython.core.magic import Magic
50 from IPython.core.magic import Magic
51 from IPython.core.payload import PayloadManager
51 from IPython.core.payload import PayloadManager
52 from IPython.core.plugin import PluginManager
52 from IPython.core.plugin import PluginManager
53 from IPython.core.prefilter import PrefilterManager, ESC_MAGIC
53 from IPython.core.prefilter import PrefilterManager, ESC_MAGIC
54 from IPython.external.Itpl import ItplNS
54 from IPython.external.Itpl import ItplNS
55 from IPython.utils import PyColorize
55 from IPython.utils import PyColorize
56 from IPython.utils import io
56 from IPython.utils import io
57 from IPython.utils import pickleshare
57 from IPython.utils import pickleshare
58 from IPython.utils.doctestreload import doctest_reload
58 from IPython.utils.doctestreload import doctest_reload
59 from IPython.utils.io import ask_yes_no, rprint
59 from IPython.utils.io import ask_yes_no, rprint
60 from IPython.utils.ipstruct import Struct
60 from IPython.utils.ipstruct import Struct
61 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
61 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
62 from IPython.utils.process import system, getoutput
62 from IPython.utils.process import system, getoutput
63 from IPython.utils.strdispatch import StrDispatch
63 from IPython.utils.strdispatch import StrDispatch
64 from IPython.utils.syspathcontext import prepended_to_syspath
64 from IPython.utils.syspathcontext import prepended_to_syspath
65 from IPython.utils.text import num_ini_spaces, format_screen, LSString, SList
65 from IPython.utils.text import num_ini_spaces, format_screen, LSString, SList
66 from IPython.utils.traitlets import (Int, Str, CBool, CaselessStrEnum, Enum,
66 from IPython.utils.traitlets import (Int, Str, CBool, CaselessStrEnum, Enum,
67 List, Unicode, Instance, Type)
67 List, Unicode, Instance, Type)
68 from IPython.utils.warn import warn, error, fatal
68 from IPython.utils.warn import warn, error, fatal
69 import IPython.core.hooks
69 import IPython.core.hooks
70
70
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72 # Globals
72 # Globals
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74
74
75 # compiled regexps for autoindent management
75 # compiled regexps for autoindent management
76 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
76 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
77
77
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79 # Utilities
79 # Utilities
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81
81
82 # store the builtin raw_input globally, and use this always, in case user code
82 # store the builtin raw_input globally, and use this always, in case user code
83 # overwrites it (like wx.py.PyShell does)
83 # overwrites it (like wx.py.PyShell does)
84 raw_input_original = raw_input
84 raw_input_original = raw_input
85
85
86 def softspace(file, newvalue):
86 def softspace(file, newvalue):
87 """Copied from code.py, to remove the dependency"""
87 """Copied from code.py, to remove the dependency"""
88
88
89 oldvalue = 0
89 oldvalue = 0
90 try:
90 try:
91 oldvalue = file.softspace
91 oldvalue = file.softspace
92 except AttributeError:
92 except AttributeError:
93 pass
93 pass
94 try:
94 try:
95 file.softspace = newvalue
95 file.softspace = newvalue
96 except (AttributeError, TypeError):
96 except (AttributeError, TypeError):
97 # "attribute-less object" or "read-only attributes"
97 # "attribute-less object" or "read-only attributes"
98 pass
98 pass
99 return oldvalue
99 return oldvalue
100
100
101
101
102 def no_op(*a, **kw): pass
102 def no_op(*a, **kw): pass
103
103
104 class SpaceInInput(Exception): pass
104 class SpaceInInput(Exception): pass
105
105
106 class Bunch: pass
106 class Bunch: pass
107
107
108
108
109 def get_default_colors():
109 def get_default_colors():
110 if sys.platform=='darwin':
110 if sys.platform=='darwin':
111 return "LightBG"
111 return "LightBG"
112 elif os.name=='nt':
112 elif os.name=='nt':
113 return 'Linux'
113 return 'Linux'
114 else:
114 else:
115 return 'Linux'
115 return 'Linux'
116
116
117
117
118 class SeparateStr(Str):
118 class SeparateStr(Str):
119 """A Str subclass to validate separate_in, separate_out, etc.
119 """A Str subclass to validate separate_in, separate_out, etc.
120
120
121 This is a Str based trait that converts '0'->'' and '\\n'->'\n'.
121 This is a Str based trait that converts '0'->'' and '\\n'->'\n'.
122 """
122 """
123
123
124 def validate(self, obj, value):
124 def validate(self, obj, value):
125 if value == '0': value = ''
125 if value == '0': value = ''
126 value = value.replace('\\n','\n')
126 value = value.replace('\\n','\n')
127 return super(SeparateStr, self).validate(obj, value)
127 return super(SeparateStr, self).validate(obj, value)
128
128
129 class MultipleInstanceError(Exception):
129 class MultipleInstanceError(Exception):
130 pass
130 pass
131
131
132
132
133 #-----------------------------------------------------------------------------
133 #-----------------------------------------------------------------------------
134 # Main IPython class
134 # Main IPython class
135 #-----------------------------------------------------------------------------
135 #-----------------------------------------------------------------------------
136
136
137
137
138 class InteractiveShell(Configurable, Magic):
138 class InteractiveShell(Configurable, Magic):
139 """An enhanced, interactive shell for Python."""
139 """An enhanced, interactive shell for Python."""
140
140
141 _instance = None
141 _instance = None
142 autocall = Enum((0,1,2), default_value=1, config=True)
142 autocall = Enum((0,1,2), default_value=1, config=True)
143 # TODO: remove all autoindent logic and put into frontends.
143 # TODO: remove all autoindent logic and put into frontends.
144 # We can't do this yet because even runlines uses the autoindent.
144 # We can't do this yet because even runlines uses the autoindent.
145 autoindent = CBool(True, config=True)
145 autoindent = CBool(True, config=True)
146 automagic = CBool(True, config=True)
146 automagic = CBool(True, config=True)
147 cache_size = Int(1000, config=True)
147 cache_size = Int(1000, config=True)
148 color_info = CBool(True, config=True)
148 color_info = CBool(True, config=True)
149 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
149 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
150 default_value=get_default_colors(), config=True)
150 default_value=get_default_colors(), config=True)
151 debug = CBool(False, config=True)
151 debug = CBool(False, config=True)
152 deep_reload = CBool(False, config=True)
152 deep_reload = CBool(False, config=True)
153 displayhook_class = Type(DisplayHook)
153 displayhook_class = Type(DisplayHook)
154 exit_now = CBool(False)
154 exit_now = CBool(False)
155 filename = Str("<ipython console>")
155 filename = Str("<ipython console>")
156 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
156 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
157
157
158 # Input splitter, to split entire cells of input into either individual
158 # Input splitter, to split entire cells of input into either individual
159 # interactive statements or whole blocks.
159 # interactive statements or whole blocks.
160 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
160 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
161 (), {})
161 (), {})
162 logstart = CBool(False, config=True)
162 logstart = CBool(False, config=True)
163 logfile = Str('', config=True)
163 logfile = Str('', config=True)
164 logappend = Str('', config=True)
164 logappend = Str('', config=True)
165 object_info_string_level = Enum((0,1,2), default_value=0,
165 object_info_string_level = Enum((0,1,2), default_value=0,
166 config=True)
166 config=True)
167 pdb = CBool(False, config=True)
167 pdb = CBool(False, config=True)
168
168
169 pprint = CBool(True, config=True)
169 pprint = CBool(True, config=True)
170 profile = Str('', config=True)
170 profile = Str('', config=True)
171 prompt_in1 = Str('In [\\#]: ', config=True)
171 prompt_in1 = Str('In [\\#]: ', config=True)
172 prompt_in2 = Str(' .\\D.: ', config=True)
172 prompt_in2 = Str(' .\\D.: ', config=True)
173 prompt_out = Str('Out[\\#]: ', config=True)
173 prompt_out = Str('Out[\\#]: ', config=True)
174 prompts_pad_left = CBool(True, config=True)
174 prompts_pad_left = CBool(True, config=True)
175 quiet = CBool(False, config=True)
175 quiet = CBool(False, config=True)
176
176
177 # The readline stuff will eventually be moved to the terminal subclass
177 # The readline stuff will eventually be moved to the terminal subclass
178 # but for now, we can't do that as readline is welded in everywhere.
178 # but for now, we can't do that as readline is welded in everywhere.
179 readline_use = CBool(True, config=True)
179 readline_use = CBool(True, config=True)
180 readline_merge_completions = CBool(True, config=True)
180 readline_merge_completions = CBool(True, config=True)
181 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
181 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
182 readline_remove_delims = Str('-/~', config=True)
182 readline_remove_delims = Str('-/~', config=True)
183 readline_parse_and_bind = List([
183 readline_parse_and_bind = List([
184 'tab: complete',
184 'tab: complete',
185 '"\C-l": clear-screen',
185 '"\C-l": clear-screen',
186 'set show-all-if-ambiguous on',
186 'set show-all-if-ambiguous on',
187 '"\C-o": tab-insert',
187 '"\C-o": tab-insert',
188 '"\M-i": " "',
188 '"\M-i": " "',
189 '"\M-o": "\d\d\d\d"',
189 '"\M-o": "\d\d\d\d"',
190 '"\M-I": "\d\d\d\d"',
190 '"\M-I": "\d\d\d\d"',
191 '"\C-r": reverse-search-history',
191 '"\C-r": reverse-search-history',
192 '"\C-s": forward-search-history',
192 '"\C-s": forward-search-history',
193 '"\C-p": history-search-backward',
193 '"\C-p": history-search-backward',
194 '"\C-n": history-search-forward',
194 '"\C-n": history-search-forward',
195 '"\e[A": history-search-backward',
195 '"\e[A": history-search-backward',
196 '"\e[B": history-search-forward',
196 '"\e[B": history-search-forward',
197 '"\C-k": kill-line',
197 '"\C-k": kill-line',
198 '"\C-u": unix-line-discard',
198 '"\C-u": unix-line-discard',
199 ], allow_none=False, config=True)
199 ], allow_none=False, config=True)
200
200
201 # TODO: this part of prompt management should be moved to the frontends.
201 # TODO: this part of prompt management should be moved to the frontends.
202 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
202 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
203 separate_in = SeparateStr('\n', config=True)
203 separate_in = SeparateStr('\n', config=True)
204 separate_out = SeparateStr('', config=True)
204 separate_out = SeparateStr('', config=True)
205 separate_out2 = SeparateStr('', config=True)
205 separate_out2 = SeparateStr('', config=True)
206 wildcards_case_sensitive = CBool(True, config=True)
206 wildcards_case_sensitive = CBool(True, config=True)
207 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
207 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
208 default_value='Context', config=True)
208 default_value='Context', config=True)
209
209
210 # Subcomponents of InteractiveShell
210 # Subcomponents of InteractiveShell
211 alias_manager = Instance('IPython.core.alias.AliasManager')
211 alias_manager = Instance('IPython.core.alias.AliasManager')
212 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
212 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
213 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
213 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
214 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
214 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
215 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
215 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
216 plugin_manager = Instance('IPython.core.plugin.PluginManager')
216 plugin_manager = Instance('IPython.core.plugin.PluginManager')
217 payload_manager = Instance('IPython.core.payload.PayloadManager')
217 payload_manager = Instance('IPython.core.payload.PayloadManager')
218
218
219 # Private interface
219 # Private interface
220 _post_execute = set()
220 _post_execute = set()
221
221
222 def __init__(self, config=None, ipython_dir=None,
222 def __init__(self, config=None, ipython_dir=None,
223 user_ns=None, user_global_ns=None,
223 user_ns=None, user_global_ns=None,
224 custom_exceptions=((), None)):
224 custom_exceptions=((), None)):
225
225
226 # This is where traits with a config_key argument are updated
226 # This is where traits with a config_key argument are updated
227 # from the values on config.
227 # from the values on config.
228 super(InteractiveShell, self).__init__(config=config)
228 super(InteractiveShell, self).__init__(config=config)
229
229
230 # These are relatively independent and stateless
230 # These are relatively independent and stateless
231 self.init_ipython_dir(ipython_dir)
231 self.init_ipython_dir(ipython_dir)
232 self.init_instance_attrs()
232 self.init_instance_attrs()
233 self.init_environment()
233 self.init_environment()
234
234
235 # Create namespaces (user_ns, user_global_ns, etc.)
235 # Create namespaces (user_ns, user_global_ns, etc.)
236 self.init_create_namespaces(user_ns, user_global_ns)
236 self.init_create_namespaces(user_ns, user_global_ns)
237 # This has to be done after init_create_namespaces because it uses
237 # This has to be done after init_create_namespaces because it uses
238 # something in self.user_ns, but before init_sys_modules, which
238 # something in self.user_ns, but before init_sys_modules, which
239 # is the first thing to modify sys.
239 # is the first thing to modify sys.
240 # TODO: When we override sys.stdout and sys.stderr before this class
240 # TODO: When we override sys.stdout and sys.stderr before this class
241 # is created, we are saving the overridden ones here. Not sure if this
241 # is created, we are saving the overridden ones here. Not sure if this
242 # is what we want to do.
242 # is what we want to do.
243 self.save_sys_module_state()
243 self.save_sys_module_state()
244 self.init_sys_modules()
244 self.init_sys_modules()
245
245
246 self.init_history()
246 self.init_history()
247 self.init_encoding()
247 self.init_encoding()
248 self.init_prefilter()
248 self.init_prefilter()
249
249
250 Magic.__init__(self, self)
250 Magic.__init__(self, self)
251
251
252 self.init_syntax_highlighting()
252 self.init_syntax_highlighting()
253 self.init_hooks()
253 self.init_hooks()
254 self.init_pushd_popd_magic()
254 self.init_pushd_popd_magic()
255 # self.init_traceback_handlers use to be here, but we moved it below
255 # self.init_traceback_handlers use to be here, but we moved it below
256 # because it and init_io have to come after init_readline.
256 # because it and init_io have to come after init_readline.
257 self.init_user_ns()
257 self.init_user_ns()
258 self.init_logger()
258 self.init_logger()
259 self.init_alias()
259 self.init_alias()
260 self.init_builtins()
260 self.init_builtins()
261
261
262 # pre_config_initialization
262 # pre_config_initialization
263 self.init_shadow_hist()
263 self.init_shadow_hist()
264
264
265 # The next section should contain everything that was in ipmaker.
265 # The next section should contain everything that was in ipmaker.
266 self.init_logstart()
266 self.init_logstart()
267
267
268 # The following was in post_config_initialization
268 # The following was in post_config_initialization
269 self.init_inspector()
269 self.init_inspector()
270 # init_readline() must come before init_io(), because init_io uses
270 # init_readline() must come before init_io(), because init_io uses
271 # readline related things.
271 # readline related things.
272 self.init_readline()
272 self.init_readline()
273 # init_completer must come after init_readline, because it needs to
273 # init_completer must come after init_readline, because it needs to
274 # know whether readline is present or not system-wide to configure the
274 # know whether readline is present or not system-wide to configure the
275 # completers, since the completion machinery can now operate
275 # completers, since the completion machinery can now operate
276 # independently of readline (e.g. over the network)
276 # independently of readline (e.g. over the network)
277 self.init_completer()
277 self.init_completer()
278 # TODO: init_io() needs to happen before init_traceback handlers
278 # TODO: init_io() needs to happen before init_traceback handlers
279 # because the traceback handlers hardcode the stdout/stderr streams.
279 # because the traceback handlers hardcode the stdout/stderr streams.
280 # This logic in in debugger.Pdb and should eventually be changed.
280 # This logic in in debugger.Pdb and should eventually be changed.
281 self.init_io()
281 self.init_io()
282 self.init_traceback_handlers(custom_exceptions)
282 self.init_traceback_handlers(custom_exceptions)
283 self.init_prompts()
283 self.init_prompts()
284 self.init_displayhook()
284 self.init_displayhook()
285 self.init_reload_doctest()
285 self.init_reload_doctest()
286 self.init_magics()
286 self.init_magics()
287 self.init_pdb()
287 self.init_pdb()
288 self.init_extension_manager()
288 self.init_extension_manager()
289 self.init_plugin_manager()
289 self.init_plugin_manager()
290 self.init_payload()
290 self.init_payload()
291 self.hooks.late_startup_hook()
291 self.hooks.late_startup_hook()
292 atexit.register(self.atexit_operations)
292 atexit.register(self.atexit_operations)
293
293
294 @classmethod
294 @classmethod
295 def instance(cls, *args, **kwargs):
295 def instance(cls, *args, **kwargs):
296 """Returns a global InteractiveShell instance."""
296 """Returns a global InteractiveShell instance."""
297 if cls._instance is None:
297 if cls._instance is None:
298 inst = cls(*args, **kwargs)
298 inst = cls(*args, **kwargs)
299 # Now make sure that the instance will also be returned by
299 # Now make sure that the instance will also be returned by
300 # the subclasses instance attribute.
300 # the subclasses instance attribute.
301 for subclass in cls.mro():
301 for subclass in cls.mro():
302 if issubclass(cls, subclass) and \
302 if issubclass(cls, subclass) and \
303 issubclass(subclass, InteractiveShell):
303 issubclass(subclass, InteractiveShell):
304 subclass._instance = inst
304 subclass._instance = inst
305 else:
305 else:
306 break
306 break
307 if isinstance(cls._instance, cls):
307 if isinstance(cls._instance, cls):
308 return cls._instance
308 return cls._instance
309 else:
309 else:
310 raise MultipleInstanceError(
310 raise MultipleInstanceError(
311 'Multiple incompatible subclass instances of '
311 'Multiple incompatible subclass instances of '
312 'InteractiveShell are being created.'
312 'InteractiveShell are being created.'
313 )
313 )
314
314
315 @classmethod
315 @classmethod
316 def initialized(cls):
316 def initialized(cls):
317 return hasattr(cls, "_instance")
317 return hasattr(cls, "_instance")
318
318
319 def get_ipython(self):
319 def get_ipython(self):
320 """Return the currently running IPython instance."""
320 """Return the currently running IPython instance."""
321 return self
321 return self
322
322
323 #-------------------------------------------------------------------------
323 #-------------------------------------------------------------------------
324 # Trait changed handlers
324 # Trait changed handlers
325 #-------------------------------------------------------------------------
325 #-------------------------------------------------------------------------
326
326
327 def _ipython_dir_changed(self, name, new):
327 def _ipython_dir_changed(self, name, new):
328 if not os.path.isdir(new):
328 if not os.path.isdir(new):
329 os.makedirs(new, mode = 0777)
329 os.makedirs(new, mode = 0777)
330
330
331 def set_autoindent(self,value=None):
331 def set_autoindent(self,value=None):
332 """Set the autoindent flag, checking for readline support.
332 """Set the autoindent flag, checking for readline support.
333
333
334 If called with no arguments, it acts as a toggle."""
334 If called with no arguments, it acts as a toggle."""
335
335
336 if not self.has_readline:
336 if not self.has_readline:
337 if os.name == 'posix':
337 if os.name == 'posix':
338 warn("The auto-indent feature requires the readline library")
338 warn("The auto-indent feature requires the readline library")
339 self.autoindent = 0
339 self.autoindent = 0
340 return
340 return
341 if value is None:
341 if value is None:
342 self.autoindent = not self.autoindent
342 self.autoindent = not self.autoindent
343 else:
343 else:
344 self.autoindent = value
344 self.autoindent = value
345
345
346 #-------------------------------------------------------------------------
346 #-------------------------------------------------------------------------
347 # init_* methods called by __init__
347 # init_* methods called by __init__
348 #-------------------------------------------------------------------------
348 #-------------------------------------------------------------------------
349
349
350 def init_ipython_dir(self, ipython_dir):
350 def init_ipython_dir(self, ipython_dir):
351 if ipython_dir is not None:
351 if ipython_dir is not None:
352 self.ipython_dir = ipython_dir
352 self.ipython_dir = ipython_dir
353 self.config.Global.ipython_dir = self.ipython_dir
353 self.config.Global.ipython_dir = self.ipython_dir
354 return
354 return
355
355
356 if hasattr(self.config.Global, 'ipython_dir'):
356 if hasattr(self.config.Global, 'ipython_dir'):
357 self.ipython_dir = self.config.Global.ipython_dir
357 self.ipython_dir = self.config.Global.ipython_dir
358 else:
358 else:
359 self.ipython_dir = get_ipython_dir()
359 self.ipython_dir = get_ipython_dir()
360
360
361 # All children can just read this
361 # All children can just read this
362 self.config.Global.ipython_dir = self.ipython_dir
362 self.config.Global.ipython_dir = self.ipython_dir
363
363
364 def init_instance_attrs(self):
364 def init_instance_attrs(self):
365 self.more = False
365 self.more = False
366
366
367 # command compiler
367 # command compiler
368 self.compile = codeop.CommandCompiler()
368 self.compile = codeop.CommandCompiler()
369
369
370 # User input buffer
370 # User input buffer
371 self.buffer = []
371 self.buffer = []
372
372
373 # Make an empty namespace, which extension writers can rely on both
373 # Make an empty namespace, which extension writers can rely on both
374 # existing and NEVER being used by ipython itself. This gives them a
374 # existing and NEVER being used by ipython itself. This gives them a
375 # convenient location for storing additional information and state
375 # convenient location for storing additional information and state
376 # their extensions may require, without fear of collisions with other
376 # their extensions may require, without fear of collisions with other
377 # ipython names that may develop later.
377 # ipython names that may develop later.
378 self.meta = Struct()
378 self.meta = Struct()
379
379
380 # Object variable to store code object waiting execution. This is
380 # Object variable to store code object waiting execution. This is
381 # used mainly by the multithreaded shells, but it can come in handy in
381 # used mainly by the multithreaded shells, but it can come in handy in
382 # other situations. No need to use a Queue here, since it's a single
382 # other situations. No need to use a Queue here, since it's a single
383 # item which gets cleared once run.
383 # item which gets cleared once run.
384 self.code_to_run = None
384 self.code_to_run = None
385
385
386 # Temporary files used for various purposes. Deleted at exit.
386 # Temporary files used for various purposes. Deleted at exit.
387 self.tempfiles = []
387 self.tempfiles = []
388
388
389 # Keep track of readline usage (later set by init_readline)
389 # Keep track of readline usage (later set by init_readline)
390 self.has_readline = False
390 self.has_readline = False
391
391
392 # keep track of where we started running (mainly for crash post-mortem)
392 # keep track of where we started running (mainly for crash post-mortem)
393 # This is not being used anywhere currently.
393 # This is not being used anywhere currently.
394 self.starting_dir = os.getcwd()
394 self.starting_dir = os.getcwd()
395
395
396 # Indentation management
396 # Indentation management
397 self.indent_current_nsp = 0
397 self.indent_current_nsp = 0
398
398
399 def init_environment(self):
399 def init_environment(self):
400 """Any changes we need to make to the user's environment."""
400 """Any changes we need to make to the user's environment."""
401 pass
401 pass
402
402
403 def init_encoding(self):
403 def init_encoding(self):
404 # Get system encoding at startup time. Certain terminals (like Emacs
404 # Get system encoding at startup time. Certain terminals (like Emacs
405 # under Win32 have it set to None, and we need to have a known valid
405 # under Win32 have it set to None, and we need to have a known valid
406 # encoding to use in the raw_input() method
406 # encoding to use in the raw_input() method
407 try:
407 try:
408 self.stdin_encoding = sys.stdin.encoding or 'ascii'
408 self.stdin_encoding = sys.stdin.encoding or 'ascii'
409 except AttributeError:
409 except AttributeError:
410 self.stdin_encoding = 'ascii'
410 self.stdin_encoding = 'ascii'
411
411
412 def init_syntax_highlighting(self):
412 def init_syntax_highlighting(self):
413 # Python source parser/formatter for syntax highlighting
413 # Python source parser/formatter for syntax highlighting
414 pyformat = PyColorize.Parser().format
414 pyformat = PyColorize.Parser().format
415 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
415 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
416
416
417 def init_pushd_popd_magic(self):
417 def init_pushd_popd_magic(self):
418 # for pushd/popd management
418 # for pushd/popd management
419 try:
419 try:
420 self.home_dir = get_home_dir()
420 self.home_dir = get_home_dir()
421 except HomeDirError, msg:
421 except HomeDirError, msg:
422 fatal(msg)
422 fatal(msg)
423
423
424 self.dir_stack = []
424 self.dir_stack = []
425
425
426 def init_logger(self):
426 def init_logger(self):
427 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
427 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
428 # local shortcut, this is used a LOT
428 # local shortcut, this is used a LOT
429 self.log = self.logger.log
429 self.log = self.logger.log
430
430
431 def init_logstart(self):
431 def init_logstart(self):
432 if self.logappend:
432 if self.logappend:
433 self.magic_logstart(self.logappend + ' append')
433 self.magic_logstart(self.logappend + ' append')
434 elif self.logfile:
434 elif self.logfile:
435 self.magic_logstart(self.logfile)
435 self.magic_logstart(self.logfile)
436 elif self.logstart:
436 elif self.logstart:
437 self.magic_logstart()
437 self.magic_logstart()
438
438
439 def init_builtins(self):
439 def init_builtins(self):
440 self.builtin_trap = BuiltinTrap(shell=self)
440 self.builtin_trap = BuiltinTrap(shell=self)
441
441
442 def init_inspector(self):
442 def init_inspector(self):
443 # Object inspector
443 # Object inspector
444 self.inspector = oinspect.Inspector(oinspect.InspectColors,
444 self.inspector = oinspect.Inspector(oinspect.InspectColors,
445 PyColorize.ANSICodeColors,
445 PyColorize.ANSICodeColors,
446 'NoColor',
446 'NoColor',
447 self.object_info_string_level)
447 self.object_info_string_level)
448
448
449 def init_io(self):
449 def init_io(self):
450 # This will just use sys.stdout and sys.stderr. If you want to
450 # This will just use sys.stdout and sys.stderr. If you want to
451 # override sys.stdout and sys.stderr themselves, you need to do that
451 # override sys.stdout and sys.stderr themselves, you need to do that
452 # *before* instantiating this class, because Term holds onto
452 # *before* instantiating this class, because Term holds onto
453 # references to the underlying streams.
453 # references to the underlying streams.
454 if sys.platform == 'win32' and self.has_readline:
454 if sys.platform == 'win32' and self.has_readline:
455 Term = io.IOTerm(cout=self.readline._outputfile,
455 Term = io.IOTerm(cout=self.readline._outputfile,
456 cerr=self.readline._outputfile)
456 cerr=self.readline._outputfile)
457 else:
457 else:
458 Term = io.IOTerm()
458 Term = io.IOTerm()
459 io.Term = Term
459 io.Term = Term
460
460
461 def init_prompts(self):
461 def init_prompts(self):
462 # TODO: This is a pass for now because the prompts are managed inside
462 # TODO: This is a pass for now because the prompts are managed inside
463 # the DisplayHook. Once there is a separate prompt manager, this
463 # the DisplayHook. Once there is a separate prompt manager, this
464 # will initialize that object and all prompt related information.
464 # will initialize that object and all prompt related information.
465 pass
465 pass
466
466
467 def init_displayhook(self):
467 def init_displayhook(self):
468 # Initialize displayhook, set in/out prompts and printing system
468 # Initialize displayhook, set in/out prompts and printing system
469 self.displayhook = self.displayhook_class(
469 self.displayhook = self.displayhook_class(
470 shell=self,
470 shell=self,
471 cache_size=self.cache_size,
471 cache_size=self.cache_size,
472 input_sep = self.separate_in,
472 input_sep = self.separate_in,
473 output_sep = self.separate_out,
473 output_sep = self.separate_out,
474 output_sep2 = self.separate_out2,
474 output_sep2 = self.separate_out2,
475 ps1 = self.prompt_in1,
475 ps1 = self.prompt_in1,
476 ps2 = self.prompt_in2,
476 ps2 = self.prompt_in2,
477 ps_out = self.prompt_out,
477 ps_out = self.prompt_out,
478 pad_left = self.prompts_pad_left
478 pad_left = self.prompts_pad_left
479 )
479 )
480 # This is a context manager that installs/revmoes the displayhook at
480 # This is a context manager that installs/revmoes the displayhook at
481 # the appropriate time.
481 # the appropriate time.
482 self.display_trap = DisplayTrap(hook=self.displayhook)
482 self.display_trap = DisplayTrap(hook=self.displayhook)
483
483
484 def init_reload_doctest(self):
484 def init_reload_doctest(self):
485 # Do a proper resetting of doctest, including the necessary displayhook
485 # Do a proper resetting of doctest, including the necessary displayhook
486 # monkeypatching
486 # monkeypatching
487 try:
487 try:
488 doctest_reload()
488 doctest_reload()
489 except ImportError:
489 except ImportError:
490 warn("doctest module does not exist.")
490 warn("doctest module does not exist.")
491
491
492 #-------------------------------------------------------------------------
492 #-------------------------------------------------------------------------
493 # Things related to injections into the sys module
493 # Things related to injections into the sys module
494 #-------------------------------------------------------------------------
494 #-------------------------------------------------------------------------
495
495
496 def save_sys_module_state(self):
496 def save_sys_module_state(self):
497 """Save the state of hooks in the sys module.
497 """Save the state of hooks in the sys module.
498
498
499 This has to be called after self.user_ns is created.
499 This has to be called after self.user_ns is created.
500 """
500 """
501 self._orig_sys_module_state = {}
501 self._orig_sys_module_state = {}
502 self._orig_sys_module_state['stdin'] = sys.stdin
502 self._orig_sys_module_state['stdin'] = sys.stdin
503 self._orig_sys_module_state['stdout'] = sys.stdout
503 self._orig_sys_module_state['stdout'] = sys.stdout
504 self._orig_sys_module_state['stderr'] = sys.stderr
504 self._orig_sys_module_state['stderr'] = sys.stderr
505 self._orig_sys_module_state['excepthook'] = sys.excepthook
505 self._orig_sys_module_state['excepthook'] = sys.excepthook
506 try:
506 try:
507 self._orig_sys_modules_main_name = self.user_ns['__name__']
507 self._orig_sys_modules_main_name = self.user_ns['__name__']
508 except KeyError:
508 except KeyError:
509 pass
509 pass
510
510
511 def restore_sys_module_state(self):
511 def restore_sys_module_state(self):
512 """Restore the state of the sys module."""
512 """Restore the state of the sys module."""
513 try:
513 try:
514 for k, v in self._orig_sys_module_state.items():
514 for k, v in self._orig_sys_module_state.iteritems():
515 setattr(sys, k, v)
515 setattr(sys, k, v)
516 except AttributeError:
516 except AttributeError:
517 pass
517 pass
518 # Reset what what done in self.init_sys_modules
518 # Reset what what done in self.init_sys_modules
519 try:
519 try:
520 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
520 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
521 except (AttributeError, KeyError):
521 except (AttributeError, KeyError):
522 pass
522 pass
523
523
524 #-------------------------------------------------------------------------
524 #-------------------------------------------------------------------------
525 # Things related to hooks
525 # Things related to hooks
526 #-------------------------------------------------------------------------
526 #-------------------------------------------------------------------------
527
527
528 def init_hooks(self):
528 def init_hooks(self):
529 # hooks holds pointers used for user-side customizations
529 # hooks holds pointers used for user-side customizations
530 self.hooks = Struct()
530 self.hooks = Struct()
531
531
532 self.strdispatchers = {}
532 self.strdispatchers = {}
533
533
534 # Set all default hooks, defined in the IPython.hooks module.
534 # Set all default hooks, defined in the IPython.hooks module.
535 hooks = IPython.core.hooks
535 hooks = IPython.core.hooks
536 for hook_name in hooks.__all__:
536 for hook_name in hooks.__all__:
537 # default hooks have priority 100, i.e. low; user hooks should have
537 # default hooks have priority 100, i.e. low; user hooks should have
538 # 0-100 priority
538 # 0-100 priority
539 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
539 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
540
540
541 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
541 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
542 """set_hook(name,hook) -> sets an internal IPython hook.
542 """set_hook(name,hook) -> sets an internal IPython hook.
543
543
544 IPython exposes some of its internal API as user-modifiable hooks. By
544 IPython exposes some of its internal API as user-modifiable hooks. By
545 adding your function to one of these hooks, you can modify IPython's
545 adding your function to one of these hooks, you can modify IPython's
546 behavior to call at runtime your own routines."""
546 behavior to call at runtime your own routines."""
547
547
548 # At some point in the future, this should validate the hook before it
548 # At some point in the future, this should validate the hook before it
549 # accepts it. Probably at least check that the hook takes the number
549 # accepts it. Probably at least check that the hook takes the number
550 # of args it's supposed to.
550 # of args it's supposed to.
551
551
552 f = types.MethodType(hook, self)
552 f = types.MethodType(hook, self)
553
553
554 # check if the hook is for strdispatcher first
554 # check if the hook is for strdispatcher first
555 if str_key is not None:
555 if str_key is not None:
556 sdp = self.strdispatchers.get(name, StrDispatch())
556 sdp = self.strdispatchers.get(name, StrDispatch())
557 sdp.add_s(str_key, f, priority )
557 sdp.add_s(str_key, f, priority )
558 self.strdispatchers[name] = sdp
558 self.strdispatchers[name] = sdp
559 return
559 return
560 if re_key is not None:
560 if re_key is not None:
561 sdp = self.strdispatchers.get(name, StrDispatch())
561 sdp = self.strdispatchers.get(name, StrDispatch())
562 sdp.add_re(re.compile(re_key), f, priority )
562 sdp.add_re(re.compile(re_key), f, priority )
563 self.strdispatchers[name] = sdp
563 self.strdispatchers[name] = sdp
564 return
564 return
565
565
566 dp = getattr(self.hooks, name, None)
566 dp = getattr(self.hooks, name, None)
567 if name not in IPython.core.hooks.__all__:
567 if name not in IPython.core.hooks.__all__:
568 print "Warning! Hook '%s' is not one of %s" % \
568 print "Warning! Hook '%s' is not one of %s" % \
569 (name, IPython.core.hooks.__all__ )
569 (name, IPython.core.hooks.__all__ )
570 if not dp:
570 if not dp:
571 dp = IPython.core.hooks.CommandChainDispatcher()
571 dp = IPython.core.hooks.CommandChainDispatcher()
572
572
573 try:
573 try:
574 dp.add(f,priority)
574 dp.add(f,priority)
575 except AttributeError:
575 except AttributeError:
576 # it was not commandchain, plain old func - replace
576 # it was not commandchain, plain old func - replace
577 dp = f
577 dp = f
578
578
579 setattr(self.hooks,name, dp)
579 setattr(self.hooks,name, dp)
580
580
581 def register_post_execute(self, func):
581 def register_post_execute(self, func):
582 """Register a function for calling after code execution.
582 """Register a function for calling after code execution.
583 """
583 """
584 if not callable(func):
584 if not callable(func):
585 raise ValueError('argument %s must be callable' % func)
585 raise ValueError('argument %s must be callable' % func)
586 self._post_execute.add(func)
586 self._post_execute.add(func)
587
587
588 #-------------------------------------------------------------------------
588 #-------------------------------------------------------------------------
589 # Things related to the "main" module
589 # Things related to the "main" module
590 #-------------------------------------------------------------------------
590 #-------------------------------------------------------------------------
591
591
592 def new_main_mod(self,ns=None):
592 def new_main_mod(self,ns=None):
593 """Return a new 'main' module object for user code execution.
593 """Return a new 'main' module object for user code execution.
594 """
594 """
595 main_mod = self._user_main_module
595 main_mod = self._user_main_module
596 init_fakemod_dict(main_mod,ns)
596 init_fakemod_dict(main_mod,ns)
597 return main_mod
597 return main_mod
598
598
599 def cache_main_mod(self,ns,fname):
599 def cache_main_mod(self,ns,fname):
600 """Cache a main module's namespace.
600 """Cache a main module's namespace.
601
601
602 When scripts are executed via %run, we must keep a reference to the
602 When scripts are executed via %run, we must keep a reference to the
603 namespace of their __main__ module (a FakeModule instance) around so
603 namespace of their __main__ module (a FakeModule instance) around so
604 that Python doesn't clear it, rendering objects defined therein
604 that Python doesn't clear it, rendering objects defined therein
605 useless.
605 useless.
606
606
607 This method keeps said reference in a private dict, keyed by the
607 This method keeps said reference in a private dict, keyed by the
608 absolute path of the module object (which corresponds to the script
608 absolute path of the module object (which corresponds to the script
609 path). This way, for multiple executions of the same script we only
609 path). This way, for multiple executions of the same script we only
610 keep one copy of the namespace (the last one), thus preventing memory
610 keep one copy of the namespace (the last one), thus preventing memory
611 leaks from old references while allowing the objects from the last
611 leaks from old references while allowing the objects from the last
612 execution to be accessible.
612 execution to be accessible.
613
613
614 Note: we can not allow the actual FakeModule instances to be deleted,
614 Note: we can not allow the actual FakeModule instances to be deleted,
615 because of how Python tears down modules (it hard-sets all their
615 because of how Python tears down modules (it hard-sets all their
616 references to None without regard for reference counts). This method
616 references to None without regard for reference counts). This method
617 must therefore make a *copy* of the given namespace, to allow the
617 must therefore make a *copy* of the given namespace, to allow the
618 original module's __dict__ to be cleared and reused.
618 original module's __dict__ to be cleared and reused.
619
619
620
620
621 Parameters
621 Parameters
622 ----------
622 ----------
623 ns : a namespace (a dict, typically)
623 ns : a namespace (a dict, typically)
624
624
625 fname : str
625 fname : str
626 Filename associated with the namespace.
626 Filename associated with the namespace.
627
627
628 Examples
628 Examples
629 --------
629 --------
630
630
631 In [10]: import IPython
631 In [10]: import IPython
632
632
633 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
633 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
634
634
635 In [12]: IPython.__file__ in _ip._main_ns_cache
635 In [12]: IPython.__file__ in _ip._main_ns_cache
636 Out[12]: True
636 Out[12]: True
637 """
637 """
638 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
638 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
639
639
640 def clear_main_mod_cache(self):
640 def clear_main_mod_cache(self):
641 """Clear the cache of main modules.
641 """Clear the cache of main modules.
642
642
643 Mainly for use by utilities like %reset.
643 Mainly for use by utilities like %reset.
644
644
645 Examples
645 Examples
646 --------
646 --------
647
647
648 In [15]: import IPython
648 In [15]: import IPython
649
649
650 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
650 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
651
651
652 In [17]: len(_ip._main_ns_cache) > 0
652 In [17]: len(_ip._main_ns_cache) > 0
653 Out[17]: True
653 Out[17]: True
654
654
655 In [18]: _ip.clear_main_mod_cache()
655 In [18]: _ip.clear_main_mod_cache()
656
656
657 In [19]: len(_ip._main_ns_cache) == 0
657 In [19]: len(_ip._main_ns_cache) == 0
658 Out[19]: True
658 Out[19]: True
659 """
659 """
660 self._main_ns_cache.clear()
660 self._main_ns_cache.clear()
661
661
662 #-------------------------------------------------------------------------
662 #-------------------------------------------------------------------------
663 # Things related to debugging
663 # Things related to debugging
664 #-------------------------------------------------------------------------
664 #-------------------------------------------------------------------------
665
665
666 def init_pdb(self):
666 def init_pdb(self):
667 # Set calling of pdb on exceptions
667 # Set calling of pdb on exceptions
668 # self.call_pdb is a property
668 # self.call_pdb is a property
669 self.call_pdb = self.pdb
669 self.call_pdb = self.pdb
670
670
671 def _get_call_pdb(self):
671 def _get_call_pdb(self):
672 return self._call_pdb
672 return self._call_pdb
673
673
674 def _set_call_pdb(self,val):
674 def _set_call_pdb(self,val):
675
675
676 if val not in (0,1,False,True):
676 if val not in (0,1,False,True):
677 raise ValueError,'new call_pdb value must be boolean'
677 raise ValueError,'new call_pdb value must be boolean'
678
678
679 # store value in instance
679 # store value in instance
680 self._call_pdb = val
680 self._call_pdb = val
681
681
682 # notify the actual exception handlers
682 # notify the actual exception handlers
683 self.InteractiveTB.call_pdb = val
683 self.InteractiveTB.call_pdb = val
684
684
685 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
685 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
686 'Control auto-activation of pdb at exceptions')
686 'Control auto-activation of pdb at exceptions')
687
687
688 def debugger(self,force=False):
688 def debugger(self,force=False):
689 """Call the pydb/pdb debugger.
689 """Call the pydb/pdb debugger.
690
690
691 Keywords:
691 Keywords:
692
692
693 - force(False): by default, this routine checks the instance call_pdb
693 - force(False): by default, this routine checks the instance call_pdb
694 flag and does not actually invoke the debugger if the flag is false.
694 flag and does not actually invoke the debugger if the flag is false.
695 The 'force' option forces the debugger to activate even if the flag
695 The 'force' option forces the debugger to activate even if the flag
696 is false.
696 is false.
697 """
697 """
698
698
699 if not (force or self.call_pdb):
699 if not (force or self.call_pdb):
700 return
700 return
701
701
702 if not hasattr(sys,'last_traceback'):
702 if not hasattr(sys,'last_traceback'):
703 error('No traceback has been produced, nothing to debug.')
703 error('No traceback has been produced, nothing to debug.')
704 return
704 return
705
705
706 # use pydb if available
706 # use pydb if available
707 if debugger.has_pydb:
707 if debugger.has_pydb:
708 from pydb import pm
708 from pydb import pm
709 else:
709 else:
710 # fallback to our internal debugger
710 # fallback to our internal debugger
711 pm = lambda : self.InteractiveTB.debugger(force=True)
711 pm = lambda : self.InteractiveTB.debugger(force=True)
712 self.history_saving_wrapper(pm)()
712 self.history_saving_wrapper(pm)()
713
713
714 #-------------------------------------------------------------------------
714 #-------------------------------------------------------------------------
715 # Things related to IPython's various namespaces
715 # Things related to IPython's various namespaces
716 #-------------------------------------------------------------------------
716 #-------------------------------------------------------------------------
717
717
718 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
718 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
719 # Create the namespace where the user will operate. user_ns is
719 # Create the namespace where the user will operate. user_ns is
720 # normally the only one used, and it is passed to the exec calls as
720 # normally the only one used, and it is passed to the exec calls as
721 # the locals argument. But we do carry a user_global_ns namespace
721 # the locals argument. But we do carry a user_global_ns namespace
722 # given as the exec 'globals' argument, This is useful in embedding
722 # given as the exec 'globals' argument, This is useful in embedding
723 # situations where the ipython shell opens in a context where the
723 # situations where the ipython shell opens in a context where the
724 # distinction between locals and globals is meaningful. For
724 # distinction between locals and globals is meaningful. For
725 # non-embedded contexts, it is just the same object as the user_ns dict.
725 # non-embedded contexts, it is just the same object as the user_ns dict.
726
726
727 # FIXME. For some strange reason, __builtins__ is showing up at user
727 # FIXME. For some strange reason, __builtins__ is showing up at user
728 # level as a dict instead of a module. This is a manual fix, but I
728 # level as a dict instead of a module. This is a manual fix, but I
729 # should really track down where the problem is coming from. Alex
729 # should really track down where the problem is coming from. Alex
730 # Schmolck reported this problem first.
730 # Schmolck reported this problem first.
731
731
732 # A useful post by Alex Martelli on this topic:
732 # A useful post by Alex Martelli on this topic:
733 # Re: inconsistent value from __builtins__
733 # Re: inconsistent value from __builtins__
734 # Von: Alex Martelli <aleaxit@yahoo.com>
734 # Von: Alex Martelli <aleaxit@yahoo.com>
735 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
735 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
736 # Gruppen: comp.lang.python
736 # Gruppen: comp.lang.python
737
737
738 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
738 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
739 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
739 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
740 # > <type 'dict'>
740 # > <type 'dict'>
741 # > >>> print type(__builtins__)
741 # > >>> print type(__builtins__)
742 # > <type 'module'>
742 # > <type 'module'>
743 # > Is this difference in return value intentional?
743 # > Is this difference in return value intentional?
744
744
745 # Well, it's documented that '__builtins__' can be either a dictionary
745 # Well, it's documented that '__builtins__' can be either a dictionary
746 # or a module, and it's been that way for a long time. Whether it's
746 # or a module, and it's been that way for a long time. Whether it's
747 # intentional (or sensible), I don't know. In any case, the idea is
747 # intentional (or sensible), I don't know. In any case, the idea is
748 # that if you need to access the built-in namespace directly, you
748 # that if you need to access the built-in namespace directly, you
749 # should start with "import __builtin__" (note, no 's') which will
749 # should start with "import __builtin__" (note, no 's') which will
750 # definitely give you a module. Yeah, it's somewhat confusing:-(.
750 # definitely give you a module. Yeah, it's somewhat confusing:-(.
751
751
752 # These routines return properly built dicts as needed by the rest of
752 # These routines return properly built dicts as needed by the rest of
753 # the code, and can also be used by extension writers to generate
753 # the code, and can also be used by extension writers to generate
754 # properly initialized namespaces.
754 # properly initialized namespaces.
755 user_ns, user_global_ns = self.make_user_namespaces(user_ns,
755 user_ns, user_global_ns = self.make_user_namespaces(user_ns,
756 user_global_ns)
756 user_global_ns)
757
757
758 # Assign namespaces
758 # Assign namespaces
759 # This is the namespace where all normal user variables live
759 # This is the namespace where all normal user variables live
760 self.user_ns = user_ns
760 self.user_ns = user_ns
761 self.user_global_ns = user_global_ns
761 self.user_global_ns = user_global_ns
762
762
763 # An auxiliary namespace that checks what parts of the user_ns were
763 # An auxiliary namespace that checks what parts of the user_ns were
764 # loaded at startup, so we can list later only variables defined in
764 # loaded at startup, so we can list later only variables defined in
765 # actual interactive use. Since it is always a subset of user_ns, it
765 # actual interactive use. Since it is always a subset of user_ns, it
766 # doesn't need to be separately tracked in the ns_table.
766 # doesn't need to be separately tracked in the ns_table.
767 self.user_ns_hidden = {}
767 self.user_ns_hidden = {}
768
768
769 # A namespace to keep track of internal data structures to prevent
769 # A namespace to keep track of internal data structures to prevent
770 # them from cluttering user-visible stuff. Will be updated later
770 # them from cluttering user-visible stuff. Will be updated later
771 self.internal_ns = {}
771 self.internal_ns = {}
772
772
773 # Now that FakeModule produces a real module, we've run into a nasty
773 # Now that FakeModule produces a real module, we've run into a nasty
774 # problem: after script execution (via %run), the module where the user
774 # problem: after script execution (via %run), the module where the user
775 # code ran is deleted. Now that this object is a true module (needed
775 # code ran is deleted. Now that this object is a true module (needed
776 # so docetst and other tools work correctly), the Python module
776 # so docetst and other tools work correctly), the Python module
777 # teardown mechanism runs over it, and sets to None every variable
777 # teardown mechanism runs over it, and sets to None every variable
778 # present in that module. Top-level references to objects from the
778 # present in that module. Top-level references to objects from the
779 # script survive, because the user_ns is updated with them. However,
779 # script survive, because the user_ns is updated with them. However,
780 # calling functions defined in the script that use other things from
780 # calling functions defined in the script that use other things from
781 # the script will fail, because the function's closure had references
781 # the script will fail, because the function's closure had references
782 # to the original objects, which are now all None. So we must protect
782 # to the original objects, which are now all None. So we must protect
783 # these modules from deletion by keeping a cache.
783 # these modules from deletion by keeping a cache.
784 #
784 #
785 # To avoid keeping stale modules around (we only need the one from the
785 # To avoid keeping stale modules around (we only need the one from the
786 # last run), we use a dict keyed with the full path to the script, so
786 # last run), we use a dict keyed with the full path to the script, so
787 # only the last version of the module is held in the cache. Note,
787 # only the last version of the module is held in the cache. Note,
788 # however, that we must cache the module *namespace contents* (their
788 # however, that we must cache the module *namespace contents* (their
789 # __dict__). Because if we try to cache the actual modules, old ones
789 # __dict__). Because if we try to cache the actual modules, old ones
790 # (uncached) could be destroyed while still holding references (such as
790 # (uncached) could be destroyed while still holding references (such as
791 # those held by GUI objects that tend to be long-lived)>
791 # those held by GUI objects that tend to be long-lived)>
792 #
792 #
793 # The %reset command will flush this cache. See the cache_main_mod()
793 # The %reset command will flush this cache. See the cache_main_mod()
794 # and clear_main_mod_cache() methods for details on use.
794 # and clear_main_mod_cache() methods for details on use.
795
795
796 # This is the cache used for 'main' namespaces
796 # This is the cache used for 'main' namespaces
797 self._main_ns_cache = {}
797 self._main_ns_cache = {}
798 # And this is the single instance of FakeModule whose __dict__ we keep
798 # And this is the single instance of FakeModule whose __dict__ we keep
799 # copying and clearing for reuse on each %run
799 # copying and clearing for reuse on each %run
800 self._user_main_module = FakeModule()
800 self._user_main_module = FakeModule()
801
801
802 # A table holding all the namespaces IPython deals with, so that
802 # A table holding all the namespaces IPython deals with, so that
803 # introspection facilities can search easily.
803 # introspection facilities can search easily.
804 self.ns_table = {'user':user_ns,
804 self.ns_table = {'user':user_ns,
805 'user_global':user_global_ns,
805 'user_global':user_global_ns,
806 'internal':self.internal_ns,
806 'internal':self.internal_ns,
807 'builtin':__builtin__.__dict__
807 'builtin':__builtin__.__dict__
808 }
808 }
809
809
810 # Similarly, track all namespaces where references can be held and that
810 # Similarly, track all namespaces where references can be held and that
811 # we can safely clear (so it can NOT include builtin). This one can be
811 # we can safely clear (so it can NOT include builtin). This one can be
812 # a simple list. Note that the main execution namespaces, user_ns and
812 # a simple list. Note that the main execution namespaces, user_ns and
813 # user_global_ns, can NOT be listed here, as clearing them blindly
813 # user_global_ns, can NOT be listed here, as clearing them blindly
814 # causes errors in object __del__ methods. Instead, the reset() method
814 # causes errors in object __del__ methods. Instead, the reset() method
815 # clears them manually and carefully.
815 # clears them manually and carefully.
816 self.ns_refs_table = [ self.user_ns_hidden,
816 self.ns_refs_table = [ self.user_ns_hidden,
817 self.internal_ns, self._main_ns_cache ]
817 self.internal_ns, self._main_ns_cache ]
818
818
819 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
819 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
820 """Return a valid local and global user interactive namespaces.
820 """Return a valid local and global user interactive namespaces.
821
821
822 This builds a dict with the minimal information needed to operate as a
822 This builds a dict with the minimal information needed to operate as a
823 valid IPython user namespace, which you can pass to the various
823 valid IPython user namespace, which you can pass to the various
824 embedding classes in ipython. The default implementation returns the
824 embedding classes in ipython. The default implementation returns the
825 same dict for both the locals and the globals to allow functions to
825 same dict for both the locals and the globals to allow functions to
826 refer to variables in the namespace. Customized implementations can
826 refer to variables in the namespace. Customized implementations can
827 return different dicts. The locals dictionary can actually be anything
827 return different dicts. The locals dictionary can actually be anything
828 following the basic mapping protocol of a dict, but the globals dict
828 following the basic mapping protocol of a dict, but the globals dict
829 must be a true dict, not even a subclass. It is recommended that any
829 must be a true dict, not even a subclass. It is recommended that any
830 custom object for the locals namespace synchronize with the globals
830 custom object for the locals namespace synchronize with the globals
831 dict somehow.
831 dict somehow.
832
832
833 Raises TypeError if the provided globals namespace is not a true dict.
833 Raises TypeError if the provided globals namespace is not a true dict.
834
834
835 Parameters
835 Parameters
836 ----------
836 ----------
837 user_ns : dict-like, optional
837 user_ns : dict-like, optional
838 The current user namespace. The items in this namespace should
838 The current user namespace. The items in this namespace should
839 be included in the output. If None, an appropriate blank
839 be included in the output. If None, an appropriate blank
840 namespace should be created.
840 namespace should be created.
841 user_global_ns : dict, optional
841 user_global_ns : dict, optional
842 The current user global namespace. The items in this namespace
842 The current user global namespace. The items in this namespace
843 should be included in the output. If None, an appropriate
843 should be included in the output. If None, an appropriate
844 blank namespace should be created.
844 blank namespace should be created.
845
845
846 Returns
846 Returns
847 -------
847 -------
848 A pair of dictionary-like object to be used as the local namespace
848 A pair of dictionary-like object to be used as the local namespace
849 of the interpreter and a dict to be used as the global namespace.
849 of the interpreter and a dict to be used as the global namespace.
850 """
850 """
851
851
852
852
853 # We must ensure that __builtin__ (without the final 's') is always
853 # We must ensure that __builtin__ (without the final 's') is always
854 # available and pointing to the __builtin__ *module*. For more details:
854 # available and pointing to the __builtin__ *module*. For more details:
855 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
855 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
856
856
857 if user_ns is None:
857 if user_ns is None:
858 # Set __name__ to __main__ to better match the behavior of the
858 # Set __name__ to __main__ to better match the behavior of the
859 # normal interpreter.
859 # normal interpreter.
860 user_ns = {'__name__' :'__main__',
860 user_ns = {'__name__' :'__main__',
861 '__builtin__' : __builtin__,
861 '__builtin__' : __builtin__,
862 '__builtins__' : __builtin__,
862 '__builtins__' : __builtin__,
863 }
863 }
864 else:
864 else:
865 user_ns.setdefault('__name__','__main__')
865 user_ns.setdefault('__name__','__main__')
866 user_ns.setdefault('__builtin__',__builtin__)
866 user_ns.setdefault('__builtin__',__builtin__)
867 user_ns.setdefault('__builtins__',__builtin__)
867 user_ns.setdefault('__builtins__',__builtin__)
868
868
869 if user_global_ns is None:
869 if user_global_ns is None:
870 user_global_ns = user_ns
870 user_global_ns = user_ns
871 if type(user_global_ns) is not dict:
871 if type(user_global_ns) is not dict:
872 raise TypeError("user_global_ns must be a true dict; got %r"
872 raise TypeError("user_global_ns must be a true dict; got %r"
873 % type(user_global_ns))
873 % type(user_global_ns))
874
874
875 return user_ns, user_global_ns
875 return user_ns, user_global_ns
876
876
877 def init_sys_modules(self):
877 def init_sys_modules(self):
878 # We need to insert into sys.modules something that looks like a
878 # We need to insert into sys.modules something that looks like a
879 # module but which accesses the IPython namespace, for shelve and
879 # module but which accesses the IPython namespace, for shelve and
880 # pickle to work interactively. Normally they rely on getting
880 # pickle to work interactively. Normally they rely on getting
881 # everything out of __main__, but for embedding purposes each IPython
881 # everything out of __main__, but for embedding purposes each IPython
882 # instance has its own private namespace, so we can't go shoving
882 # instance has its own private namespace, so we can't go shoving
883 # everything into __main__.
883 # everything into __main__.
884
884
885 # note, however, that we should only do this for non-embedded
885 # note, however, that we should only do this for non-embedded
886 # ipythons, which really mimic the __main__.__dict__ with their own
886 # ipythons, which really mimic the __main__.__dict__ with their own
887 # namespace. Embedded instances, on the other hand, should not do
887 # namespace. Embedded instances, on the other hand, should not do
888 # this because they need to manage the user local/global namespaces
888 # this because they need to manage the user local/global namespaces
889 # only, but they live within a 'normal' __main__ (meaning, they
889 # only, but they live within a 'normal' __main__ (meaning, they
890 # shouldn't overtake the execution environment of the script they're
890 # shouldn't overtake the execution environment of the script they're
891 # embedded in).
891 # embedded in).
892
892
893 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
893 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
894
894
895 try:
895 try:
896 main_name = self.user_ns['__name__']
896 main_name = self.user_ns['__name__']
897 except KeyError:
897 except KeyError:
898 raise KeyError('user_ns dictionary MUST have a "__name__" key')
898 raise KeyError('user_ns dictionary MUST have a "__name__" key')
899 else:
899 else:
900 sys.modules[main_name] = FakeModule(self.user_ns)
900 sys.modules[main_name] = FakeModule(self.user_ns)
901
901
902 def init_user_ns(self):
902 def init_user_ns(self):
903 """Initialize all user-visible namespaces to their minimum defaults.
903 """Initialize all user-visible namespaces to their minimum defaults.
904
904
905 Certain history lists are also initialized here, as they effectively
905 Certain history lists are also initialized here, as they effectively
906 act as user namespaces.
906 act as user namespaces.
907
907
908 Notes
908 Notes
909 -----
909 -----
910 All data structures here are only filled in, they are NOT reset by this
910 All data structures here are only filled in, they are NOT reset by this
911 method. If they were not empty before, data will simply be added to
911 method. If they were not empty before, data will simply be added to
912 therm.
912 therm.
913 """
913 """
914 # This function works in two parts: first we put a few things in
914 # This function works in two parts: first we put a few things in
915 # user_ns, and we sync that contents into user_ns_hidden so that these
915 # user_ns, and we sync that contents into user_ns_hidden so that these
916 # initial variables aren't shown by %who. After the sync, we add the
916 # initial variables aren't shown by %who. After the sync, we add the
917 # rest of what we *do* want the user to see with %who even on a new
917 # rest of what we *do* want the user to see with %who even on a new
918 # session (probably nothing, so theye really only see their own stuff)
918 # session (probably nothing, so theye really only see their own stuff)
919
919
920 # The user dict must *always* have a __builtin__ reference to the
920 # The user dict must *always* have a __builtin__ reference to the
921 # Python standard __builtin__ namespace, which must be imported.
921 # Python standard __builtin__ namespace, which must be imported.
922 # This is so that certain operations in prompt evaluation can be
922 # This is so that certain operations in prompt evaluation can be
923 # reliably executed with builtins. Note that we can NOT use
923 # reliably executed with builtins. Note that we can NOT use
924 # __builtins__ (note the 's'), because that can either be a dict or a
924 # __builtins__ (note the 's'), because that can either be a dict or a
925 # module, and can even mutate at runtime, depending on the context
925 # module, and can even mutate at runtime, depending on the context
926 # (Python makes no guarantees on it). In contrast, __builtin__ is
926 # (Python makes no guarantees on it). In contrast, __builtin__ is
927 # always a module object, though it must be explicitly imported.
927 # always a module object, though it must be explicitly imported.
928
928
929 # For more details:
929 # For more details:
930 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
930 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
931 ns = dict(__builtin__ = __builtin__)
931 ns = dict(__builtin__ = __builtin__)
932
932
933 # Put 'help' in the user namespace
933 # Put 'help' in the user namespace
934 try:
934 try:
935 from site import _Helper
935 from site import _Helper
936 ns['help'] = _Helper()
936 ns['help'] = _Helper()
937 except ImportError:
937 except ImportError:
938 warn('help() not available - check site.py')
938 warn('help() not available - check site.py')
939
939
940 # make global variables for user access to the histories
940 # make global variables for user access to the histories
941 ns['_ih'] = self.input_hist
941 ns['_ih'] = self.input_hist
942 ns['_oh'] = self.output_hist
942 ns['_oh'] = self.output_hist
943 ns['_dh'] = self.dir_hist
943 ns['_dh'] = self.dir_hist
944
944
945 ns['_sh'] = shadowns
945 ns['_sh'] = shadowns
946
946
947 # user aliases to input and output histories. These shouldn't show up
947 # user aliases to input and output histories. These shouldn't show up
948 # in %who, as they can have very large reprs.
948 # in %who, as they can have very large reprs.
949 ns['In'] = self.input_hist
949 ns['In'] = self.input_hist
950 ns['Out'] = self.output_hist
950 ns['Out'] = self.output_hist
951
951
952 # Store myself as the public api!!!
952 # Store myself as the public api!!!
953 ns['get_ipython'] = self.get_ipython
953 ns['get_ipython'] = self.get_ipython
954
954
955 # Sync what we've added so far to user_ns_hidden so these aren't seen
955 # Sync what we've added so far to user_ns_hidden so these aren't seen
956 # by %who
956 # by %who
957 self.user_ns_hidden.update(ns)
957 self.user_ns_hidden.update(ns)
958
958
959 # Anything put into ns now would show up in %who. Think twice before
959 # Anything put into ns now would show up in %who. Think twice before
960 # putting anything here, as we really want %who to show the user their
960 # putting anything here, as we really want %who to show the user their
961 # stuff, not our variables.
961 # stuff, not our variables.
962
962
963 # Finally, update the real user's namespace
963 # Finally, update the real user's namespace
964 self.user_ns.update(ns)
964 self.user_ns.update(ns)
965
965
966
966
967 def reset(self):
967 def reset(self):
968 """Clear all internal namespaces.
968 """Clear all internal namespaces.
969
969
970 Note that this is much more aggressive than %reset, since it clears
970 Note that this is much more aggressive than %reset, since it clears
971 fully all namespaces, as well as all input/output lists.
971 fully all namespaces, as well as all input/output lists.
972 """
972 """
973 self.alias_manager.clear_aliases()
973 self.alias_manager.clear_aliases()
974
974
975 # Clear input and output histories
975 # Clear input and output histories
976 self.input_hist[:] = []
976 self.input_hist[:] = []
977 self.input_hist_raw[:] = []
977 self.input_hist_raw[:] = []
978 self.output_hist.clear()
978 self.output_hist.clear()
979
979
980 # Clear namespaces holding user references
980 # Clear namespaces holding user references
981 for ns in self.ns_refs_table:
981 for ns in self.ns_refs_table:
982 ns.clear()
982 ns.clear()
983
983
984 # The main execution namespaces must be cleared very carefully,
984 # The main execution namespaces must be cleared very carefully,
985 # skipping the deletion of the builtin-related keys, because doing so
985 # skipping the deletion of the builtin-related keys, because doing so
986 # would cause errors in many object's __del__ methods.
986 # would cause errors in many object's __del__ methods.
987 for ns in [self.user_ns, self.user_global_ns]:
987 for ns in [self.user_ns, self.user_global_ns]:
988 drop_keys = set(ns.keys())
988 drop_keys = set(ns.keys())
989 drop_keys.discard('__builtin__')
989 drop_keys.discard('__builtin__')
990 drop_keys.discard('__builtins__')
990 drop_keys.discard('__builtins__')
991 for k in drop_keys:
991 for k in drop_keys:
992 del ns[k]
992 del ns[k]
993
993
994 # Restore the user namespaces to minimal usability
994 # Restore the user namespaces to minimal usability
995 self.init_user_ns()
995 self.init_user_ns()
996
996
997 # Restore the default and user aliases
997 # Restore the default and user aliases
998 self.alias_manager.init_aliases()
998 self.alias_manager.init_aliases()
999
999
1000 def reset_selective(self, regex=None):
1000 def reset_selective(self, regex=None):
1001 """Clear selective variables from internal namespaces based on a
1001 """Clear selective variables from internal namespaces based on a
1002 specified regular expression.
1002 specified regular expression.
1003
1003
1004 Parameters
1004 Parameters
1005 ----------
1005 ----------
1006 regex : string or compiled pattern, optional
1006 regex : string or compiled pattern, optional
1007 A regular expression pattern that will be used in searching
1007 A regular expression pattern that will be used in searching
1008 variable names in the users namespaces.
1008 variable names in the users namespaces.
1009 """
1009 """
1010 if regex is not None:
1010 if regex is not None:
1011 try:
1011 try:
1012 m = re.compile(regex)
1012 m = re.compile(regex)
1013 except TypeError:
1013 except TypeError:
1014 raise TypeError('regex must be a string or compiled pattern')
1014 raise TypeError('regex must be a string or compiled pattern')
1015 # Search for keys in each namespace that match the given regex
1015 # Search for keys in each namespace that match the given regex
1016 # If a match is found, delete the key/value pair.
1016 # If a match is found, delete the key/value pair.
1017 for ns in self.ns_refs_table:
1017 for ns in self.ns_refs_table:
1018 for var in ns:
1018 for var in ns:
1019 if m.search(var):
1019 if m.search(var):
1020 del ns[var]
1020 del ns[var]
1021
1021
1022 def push(self, variables, interactive=True):
1022 def push(self, variables, interactive=True):
1023 """Inject a group of variables into the IPython user namespace.
1023 """Inject a group of variables into the IPython user namespace.
1024
1024
1025 Parameters
1025 Parameters
1026 ----------
1026 ----------
1027 variables : dict, str or list/tuple of str
1027 variables : dict, str or list/tuple of str
1028 The variables to inject into the user's namespace. If a dict, a
1028 The variables to inject into the user's namespace. If a dict, a
1029 simple update is done. If a str, the string is assumed to have
1029 simple update is done. If a str, the string is assumed to have
1030 variable names separated by spaces. A list/tuple of str can also
1030 variable names separated by spaces. A list/tuple of str can also
1031 be used to give the variable names. If just the variable names are
1031 be used to give the variable names. If just the variable names are
1032 give (list/tuple/str) then the variable values looked up in the
1032 give (list/tuple/str) then the variable values looked up in the
1033 callers frame.
1033 callers frame.
1034 interactive : bool
1034 interactive : bool
1035 If True (default), the variables will be listed with the ``who``
1035 If True (default), the variables will be listed with the ``who``
1036 magic.
1036 magic.
1037 """
1037 """
1038 vdict = None
1038 vdict = None
1039
1039
1040 # We need a dict of name/value pairs to do namespace updates.
1040 # We need a dict of name/value pairs to do namespace updates.
1041 if isinstance(variables, dict):
1041 if isinstance(variables, dict):
1042 vdict = variables
1042 vdict = variables
1043 elif isinstance(variables, (basestring, list, tuple)):
1043 elif isinstance(variables, (basestring, list, tuple)):
1044 if isinstance(variables, basestring):
1044 if isinstance(variables, basestring):
1045 vlist = variables.split()
1045 vlist = variables.split()
1046 else:
1046 else:
1047 vlist = variables
1047 vlist = variables
1048 vdict = {}
1048 vdict = {}
1049 cf = sys._getframe(1)
1049 cf = sys._getframe(1)
1050 for name in vlist:
1050 for name in vlist:
1051 try:
1051 try:
1052 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1052 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1053 except:
1053 except:
1054 print ('Could not get variable %s from %s' %
1054 print ('Could not get variable %s from %s' %
1055 (name,cf.f_code.co_name))
1055 (name,cf.f_code.co_name))
1056 else:
1056 else:
1057 raise ValueError('variables must be a dict/str/list/tuple')
1057 raise ValueError('variables must be a dict/str/list/tuple')
1058
1058
1059 # Propagate variables to user namespace
1059 # Propagate variables to user namespace
1060 self.user_ns.update(vdict)
1060 self.user_ns.update(vdict)
1061
1061
1062 # And configure interactive visibility
1062 # And configure interactive visibility
1063 config_ns = self.user_ns_hidden
1063 config_ns = self.user_ns_hidden
1064 if interactive:
1064 if interactive:
1065 for name, val in vdict.iteritems():
1065 for name, val in vdict.iteritems():
1066 config_ns.pop(name, None)
1066 config_ns.pop(name, None)
1067 else:
1067 else:
1068 for name,val in vdict.iteritems():
1068 for name,val in vdict.iteritems():
1069 config_ns[name] = val
1069 config_ns[name] = val
1070
1070
1071 #-------------------------------------------------------------------------
1071 #-------------------------------------------------------------------------
1072 # Things related to object introspection
1072 # Things related to object introspection
1073 #-------------------------------------------------------------------------
1073 #-------------------------------------------------------------------------
1074
1074
1075 def _ofind(self, oname, namespaces=None):
1075 def _ofind(self, oname, namespaces=None):
1076 """Find an object in the available namespaces.
1076 """Find an object in the available namespaces.
1077
1077
1078 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1078 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1079
1079
1080 Has special code to detect magic functions.
1080 Has special code to detect magic functions.
1081 """
1081 """
1082 #oname = oname.strip()
1082 #oname = oname.strip()
1083 #print '1- oname: <%r>' % oname # dbg
1083 #print '1- oname: <%r>' % oname # dbg
1084 try:
1084 try:
1085 oname = oname.strip().encode('ascii')
1085 oname = oname.strip().encode('ascii')
1086 #print '2- oname: <%r>' % oname # dbg
1086 #print '2- oname: <%r>' % oname # dbg
1087 except UnicodeEncodeError:
1087 except UnicodeEncodeError:
1088 print 'Python identifiers can only contain ascii characters.'
1088 print 'Python identifiers can only contain ascii characters.'
1089 return dict(found=False)
1089 return dict(found=False)
1090
1090
1091 alias_ns = None
1091 alias_ns = None
1092 if namespaces is None:
1092 if namespaces is None:
1093 # Namespaces to search in:
1093 # Namespaces to search in:
1094 # Put them in a list. The order is important so that we
1094 # Put them in a list. The order is important so that we
1095 # find things in the same order that Python finds them.
1095 # find things in the same order that Python finds them.
1096 namespaces = [ ('Interactive', self.user_ns),
1096 namespaces = [ ('Interactive', self.user_ns),
1097 ('IPython internal', self.internal_ns),
1097 ('IPython internal', self.internal_ns),
1098 ('Python builtin', __builtin__.__dict__),
1098 ('Python builtin', __builtin__.__dict__),
1099 ('Alias', self.alias_manager.alias_table),
1099 ('Alias', self.alias_manager.alias_table),
1100 ]
1100 ]
1101 alias_ns = self.alias_manager.alias_table
1101 alias_ns = self.alias_manager.alias_table
1102
1102
1103 # initialize results to 'null'
1103 # initialize results to 'null'
1104 found = False; obj = None; ospace = None; ds = None;
1104 found = False; obj = None; ospace = None; ds = None;
1105 ismagic = False; isalias = False; parent = None
1105 ismagic = False; isalias = False; parent = None
1106
1106
1107 # We need to special-case 'print', which as of python2.6 registers as a
1107 # We need to special-case 'print', which as of python2.6 registers as a
1108 # function but should only be treated as one if print_function was
1108 # function but should only be treated as one if print_function was
1109 # loaded with a future import. In this case, just bail.
1109 # loaded with a future import. In this case, just bail.
1110 if (oname == 'print' and not (self.compile.compiler.flags &
1110 if (oname == 'print' and not (self.compile.compiler.flags &
1111 __future__.CO_FUTURE_PRINT_FUNCTION)):
1111 __future__.CO_FUTURE_PRINT_FUNCTION)):
1112 return {'found':found, 'obj':obj, 'namespace':ospace,
1112 return {'found':found, 'obj':obj, 'namespace':ospace,
1113 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1113 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1114
1114
1115 # Look for the given name by splitting it in parts. If the head is
1115 # Look for the given name by splitting it in parts. If the head is
1116 # found, then we look for all the remaining parts as members, and only
1116 # found, then we look for all the remaining parts as members, and only
1117 # declare success if we can find them all.
1117 # declare success if we can find them all.
1118 oname_parts = oname.split('.')
1118 oname_parts = oname.split('.')
1119 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1119 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1120 for nsname,ns in namespaces:
1120 for nsname,ns in namespaces:
1121 try:
1121 try:
1122 obj = ns[oname_head]
1122 obj = ns[oname_head]
1123 except KeyError:
1123 except KeyError:
1124 continue
1124 continue
1125 else:
1125 else:
1126 #print 'oname_rest:', oname_rest # dbg
1126 #print 'oname_rest:', oname_rest # dbg
1127 for part in oname_rest:
1127 for part in oname_rest:
1128 try:
1128 try:
1129 parent = obj
1129 parent = obj
1130 obj = getattr(obj,part)
1130 obj = getattr(obj,part)
1131 except:
1131 except:
1132 # Blanket except b/c some badly implemented objects
1132 # Blanket except b/c some badly implemented objects
1133 # allow __getattr__ to raise exceptions other than
1133 # allow __getattr__ to raise exceptions other than
1134 # AttributeError, which then crashes IPython.
1134 # AttributeError, which then crashes IPython.
1135 break
1135 break
1136 else:
1136 else:
1137 # If we finish the for loop (no break), we got all members
1137 # If we finish the for loop (no break), we got all members
1138 found = True
1138 found = True
1139 ospace = nsname
1139 ospace = nsname
1140 if ns == alias_ns:
1140 if ns == alias_ns:
1141 isalias = True
1141 isalias = True
1142 break # namespace loop
1142 break # namespace loop
1143
1143
1144 # Try to see if it's magic
1144 # Try to see if it's magic
1145 if not found:
1145 if not found:
1146 if oname.startswith(ESC_MAGIC):
1146 if oname.startswith(ESC_MAGIC):
1147 oname = oname[1:]
1147 oname = oname[1:]
1148 obj = getattr(self,'magic_'+oname,None)
1148 obj = getattr(self,'magic_'+oname,None)
1149 if obj is not None:
1149 if obj is not None:
1150 found = True
1150 found = True
1151 ospace = 'IPython internal'
1151 ospace = 'IPython internal'
1152 ismagic = True
1152 ismagic = True
1153
1153
1154 # Last try: special-case some literals like '', [], {}, etc:
1154 # Last try: special-case some literals like '', [], {}, etc:
1155 if not found and oname_head in ["''",'""','[]','{}','()']:
1155 if not found and oname_head in ["''",'""','[]','{}','()']:
1156 obj = eval(oname_head)
1156 obj = eval(oname_head)
1157 found = True
1157 found = True
1158 ospace = 'Interactive'
1158 ospace = 'Interactive'
1159
1159
1160 return {'found':found, 'obj':obj, 'namespace':ospace,
1160 return {'found':found, 'obj':obj, 'namespace':ospace,
1161 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1161 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1162
1162
1163 def _ofind_property(self, oname, info):
1163 def _ofind_property(self, oname, info):
1164 """Second part of object finding, to look for property details."""
1164 """Second part of object finding, to look for property details."""
1165 if info.found:
1165 if info.found:
1166 # Get the docstring of the class property if it exists.
1166 # Get the docstring of the class property if it exists.
1167 path = oname.split('.')
1167 path = oname.split('.')
1168 root = '.'.join(path[:-1])
1168 root = '.'.join(path[:-1])
1169 if info.parent is not None:
1169 if info.parent is not None:
1170 try:
1170 try:
1171 target = getattr(info.parent, '__class__')
1171 target = getattr(info.parent, '__class__')
1172 # The object belongs to a class instance.
1172 # The object belongs to a class instance.
1173 try:
1173 try:
1174 target = getattr(target, path[-1])
1174 target = getattr(target, path[-1])
1175 # The class defines the object.
1175 # The class defines the object.
1176 if isinstance(target, property):
1176 if isinstance(target, property):
1177 oname = root + '.__class__.' + path[-1]
1177 oname = root + '.__class__.' + path[-1]
1178 info = Struct(self._ofind(oname))
1178 info = Struct(self._ofind(oname))
1179 except AttributeError: pass
1179 except AttributeError: pass
1180 except AttributeError: pass
1180 except AttributeError: pass
1181
1181
1182 # We return either the new info or the unmodified input if the object
1182 # We return either the new info or the unmodified input if the object
1183 # hadn't been found
1183 # hadn't been found
1184 return info
1184 return info
1185
1185
1186 def _object_find(self, oname, namespaces=None):
1186 def _object_find(self, oname, namespaces=None):
1187 """Find an object and return a struct with info about it."""
1187 """Find an object and return a struct with info about it."""
1188 inf = Struct(self._ofind(oname, namespaces))
1188 inf = Struct(self._ofind(oname, namespaces))
1189 return Struct(self._ofind_property(oname, inf))
1189 return Struct(self._ofind_property(oname, inf))
1190
1190
1191 def _inspect(self, meth, oname, namespaces=None, **kw):
1191 def _inspect(self, meth, oname, namespaces=None, **kw):
1192 """Generic interface to the inspector system.
1192 """Generic interface to the inspector system.
1193
1193
1194 This function is meant to be called by pdef, pdoc & friends."""
1194 This function is meant to be called by pdef, pdoc & friends."""
1195 info = self._object_find(oname)
1195 info = self._object_find(oname)
1196 if info.found:
1196 if info.found:
1197 pmethod = getattr(self.inspector, meth)
1197 pmethod = getattr(self.inspector, meth)
1198 formatter = format_screen if info.ismagic else None
1198 formatter = format_screen if info.ismagic else None
1199 if meth == 'pdoc':
1199 if meth == 'pdoc':
1200 pmethod(info.obj, oname, formatter)
1200 pmethod(info.obj, oname, formatter)
1201 elif meth == 'pinfo':
1201 elif meth == 'pinfo':
1202 pmethod(info.obj, oname, formatter, info, **kw)
1202 pmethod(info.obj, oname, formatter, info, **kw)
1203 else:
1203 else:
1204 pmethod(info.obj, oname)
1204 pmethod(info.obj, oname)
1205 else:
1205 else:
1206 print 'Object `%s` not found.' % oname
1206 print 'Object `%s` not found.' % oname
1207 return 'not found' # so callers can take other action
1207 return 'not found' # so callers can take other action
1208
1208
1209 def object_inspect(self, oname):
1209 def object_inspect(self, oname):
1210 info = self._object_find(oname)
1210 info = self._object_find(oname)
1211 if info.found:
1211 if info.found:
1212 return self.inspector.info(info.obj, oname, info=info)
1212 return self.inspector.info(info.obj, oname, info=info)
1213 else:
1213 else:
1214 return oinspect.object_info(name=oname, found=False)
1214 return oinspect.object_info(name=oname, found=False)
1215
1215
1216 #-------------------------------------------------------------------------
1216 #-------------------------------------------------------------------------
1217 # Things related to history management
1217 # Things related to history management
1218 #-------------------------------------------------------------------------
1218 #-------------------------------------------------------------------------
1219
1219
1220 def init_history(self):
1220 def init_history(self):
1221 # List of input with multi-line handling.
1221 # List of input with multi-line handling.
1222 self.input_hist = InputList()
1222 self.input_hist = InputList()
1223 # This one will hold the 'raw' input history, without any
1223 # This one will hold the 'raw' input history, without any
1224 # pre-processing. This will allow users to retrieve the input just as
1224 # pre-processing. This will allow users to retrieve the input just as
1225 # it was exactly typed in by the user, with %hist -r.
1225 # it was exactly typed in by the user, with %hist -r.
1226 self.input_hist_raw = InputList()
1226 self.input_hist_raw = InputList()
1227
1227
1228 # list of visited directories
1228 # list of visited directories
1229 try:
1229 try:
1230 self.dir_hist = [os.getcwd()]
1230 self.dir_hist = [os.getcwd()]
1231 except OSError:
1231 except OSError:
1232 self.dir_hist = []
1232 self.dir_hist = []
1233
1233
1234 # dict of output history
1234 # dict of output history
1235 self.output_hist = {}
1235 self.output_hist = {}
1236
1236
1237 # Now the history file
1237 # Now the history file
1238 if self.profile:
1238 if self.profile:
1239 histfname = 'history-%s' % self.profile
1239 histfname = 'history-%s' % self.profile
1240 else:
1240 else:
1241 histfname = 'history'
1241 histfname = 'history'
1242 self.histfile = os.path.join(self.ipython_dir, histfname)
1242 self.histfile = os.path.join(self.ipython_dir, histfname)
1243
1243
1244 # Fill the history zero entry, user counter starts at 1
1244 # Fill the history zero entry, user counter starts at 1
1245 self.input_hist.append('\n')
1245 self.input_hist.append('\n')
1246 self.input_hist_raw.append('\n')
1246 self.input_hist_raw.append('\n')
1247
1247
1248 def init_shadow_hist(self):
1248 def init_shadow_hist(self):
1249 try:
1249 try:
1250 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1250 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1251 except UnicodeDecodeError:
1251 except UnicodeDecodeError:
1252 print "Your ipython_dir can't be decoded to unicode!"
1252 print "Your ipython_dir can't be decoded to unicode!"
1253 print "Please set HOME environment variable to something that"
1253 print "Please set HOME environment variable to something that"
1254 print r"only has ASCII characters, e.g. c:\home"
1254 print r"only has ASCII characters, e.g. c:\home"
1255 print "Now it is", self.ipython_dir
1255 print "Now it is", self.ipython_dir
1256 sys.exit()
1256 sys.exit()
1257 self.shadowhist = ipcorehist.ShadowHist(self.db)
1257 self.shadowhist = ipcorehist.ShadowHist(self.db)
1258
1258
1259 def savehist(self):
1259 def savehist(self):
1260 """Save input history to a file (via readline library)."""
1260 """Save input history to a file (via readline library)."""
1261
1261
1262 try:
1262 try:
1263 self.readline.write_history_file(self.histfile)
1263 self.readline.write_history_file(self.histfile)
1264 except:
1264 except:
1265 print 'Unable to save IPython command history to file: ' + \
1265 print 'Unable to save IPython command history to file: ' + \
1266 `self.histfile`
1266 `self.histfile`
1267
1267
1268 def reloadhist(self):
1268 def reloadhist(self):
1269 """Reload the input history from disk file."""
1269 """Reload the input history from disk file."""
1270
1270
1271 try:
1271 try:
1272 self.readline.clear_history()
1272 self.readline.clear_history()
1273 self.readline.read_history_file(self.shell.histfile)
1273 self.readline.read_history_file(self.shell.histfile)
1274 except AttributeError:
1274 except AttributeError:
1275 pass
1275 pass
1276
1276
1277 def history_saving_wrapper(self, func):
1277 def history_saving_wrapper(self, func):
1278 """ Wrap func for readline history saving
1278 """ Wrap func for readline history saving
1279
1279
1280 Convert func into callable that saves & restores
1280 Convert func into callable that saves & restores
1281 history around the call """
1281 history around the call """
1282
1282
1283 if self.has_readline:
1283 if self.has_readline:
1284 from IPython.utils import rlineimpl as readline
1284 from IPython.utils import rlineimpl as readline
1285 else:
1285 else:
1286 return func
1286 return func
1287
1287
1288 def wrapper():
1288 def wrapper():
1289 self.savehist()
1289 self.savehist()
1290 try:
1290 try:
1291 func()
1291 func()
1292 finally:
1292 finally:
1293 readline.read_history_file(self.histfile)
1293 readline.read_history_file(self.histfile)
1294 return wrapper
1294 return wrapper
1295
1295
1296 def get_history(self, index=None, raw=False, output=True):
1296 def get_history(self, index=None, raw=False, output=True):
1297 """Get the history list.
1297 """Get the history list.
1298
1298
1299 Get the input and output history.
1299 Get the input and output history.
1300
1300
1301 Parameters
1301 Parameters
1302 ----------
1302 ----------
1303 index : n or (n1, n2) or None
1303 index : n or (n1, n2) or None
1304 If n, then the last entries. If a tuple, then all in
1304 If n, then the last entries. If a tuple, then all in
1305 range(n1, n2). If None, then all entries. Raises IndexError if
1305 range(n1, n2). If None, then all entries. Raises IndexError if
1306 the format of index is incorrect.
1306 the format of index is incorrect.
1307 raw : bool
1307 raw : bool
1308 If True, return the raw input.
1308 If True, return the raw input.
1309 output : bool
1309 output : bool
1310 If True, then return the output as well.
1310 If True, then return the output as well.
1311
1311
1312 Returns
1312 Returns
1313 -------
1313 -------
1314 If output is True, then return a dict of tuples, keyed by the prompt
1314 If output is True, then return a dict of tuples, keyed by the prompt
1315 numbers and with values of (input, output). If output is False, then
1315 numbers and with values of (input, output). If output is False, then
1316 a dict, keyed by the prompt number with the values of input. Raises
1316 a dict, keyed by the prompt number with the values of input. Raises
1317 IndexError if no history is found.
1317 IndexError if no history is found.
1318 """
1318 """
1319 if raw:
1319 if raw:
1320 input_hist = self.input_hist_raw
1320 input_hist = self.input_hist_raw
1321 else:
1321 else:
1322 input_hist = self.input_hist
1322 input_hist = self.input_hist
1323 if output:
1323 if output:
1324 output_hist = self.user_ns['Out']
1324 output_hist = self.user_ns['Out']
1325 n = len(input_hist)
1325 n = len(input_hist)
1326 if index is None:
1326 if index is None:
1327 start=0; stop=n
1327 start=0; stop=n
1328 elif isinstance(index, int):
1328 elif isinstance(index, int):
1329 start=n-index; stop=n
1329 start=n-index; stop=n
1330 elif isinstance(index, tuple) and len(index) == 2:
1330 elif isinstance(index, tuple) and len(index) == 2:
1331 start=index[0]; stop=index[1]
1331 start=index[0]; stop=index[1]
1332 else:
1332 else:
1333 raise IndexError('Not a valid index for the input history: %r'
1333 raise IndexError('Not a valid index for the input history: %r'
1334 % index)
1334 % index)
1335 hist = {}
1335 hist = {}
1336 for i in range(start, stop):
1336 for i in range(start, stop):
1337 if output:
1337 if output:
1338 hist[i] = (input_hist[i], output_hist.get(i))
1338 hist[i] = (input_hist[i], output_hist.get(i))
1339 else:
1339 else:
1340 hist[i] = input_hist[i]
1340 hist[i] = input_hist[i]
1341 if len(hist)==0:
1341 if len(hist)==0:
1342 raise IndexError('No history for range of indices: %r' % index)
1342 raise IndexError('No history for range of indices: %r' % index)
1343 return hist
1343 return hist
1344
1344
1345 #-------------------------------------------------------------------------
1345 #-------------------------------------------------------------------------
1346 # Things related to exception handling and tracebacks (not debugging)
1346 # Things related to exception handling and tracebacks (not debugging)
1347 #-------------------------------------------------------------------------
1347 #-------------------------------------------------------------------------
1348
1348
1349 def init_traceback_handlers(self, custom_exceptions):
1349 def init_traceback_handlers(self, custom_exceptions):
1350 # Syntax error handler.
1350 # Syntax error handler.
1351 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1351 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1352
1352
1353 # The interactive one is initialized with an offset, meaning we always
1353 # The interactive one is initialized with an offset, meaning we always
1354 # want to remove the topmost item in the traceback, which is our own
1354 # want to remove the topmost item in the traceback, which is our own
1355 # internal code. Valid modes: ['Plain','Context','Verbose']
1355 # internal code. Valid modes: ['Plain','Context','Verbose']
1356 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1356 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1357 color_scheme='NoColor',
1357 color_scheme='NoColor',
1358 tb_offset = 1)
1358 tb_offset = 1)
1359
1359
1360 # The instance will store a pointer to the system-wide exception hook,
1360 # The instance will store a pointer to the system-wide exception hook,
1361 # so that runtime code (such as magics) can access it. This is because
1361 # so that runtime code (such as magics) can access it. This is because
1362 # during the read-eval loop, it may get temporarily overwritten.
1362 # during the read-eval loop, it may get temporarily overwritten.
1363 self.sys_excepthook = sys.excepthook
1363 self.sys_excepthook = sys.excepthook
1364
1364
1365 # and add any custom exception handlers the user may have specified
1365 # and add any custom exception handlers the user may have specified
1366 self.set_custom_exc(*custom_exceptions)
1366 self.set_custom_exc(*custom_exceptions)
1367
1367
1368 # Set the exception mode
1368 # Set the exception mode
1369 self.InteractiveTB.set_mode(mode=self.xmode)
1369 self.InteractiveTB.set_mode(mode=self.xmode)
1370
1370
1371 def set_custom_exc(self, exc_tuple, handler):
1371 def set_custom_exc(self, exc_tuple, handler):
1372 """set_custom_exc(exc_tuple,handler)
1372 """set_custom_exc(exc_tuple,handler)
1373
1373
1374 Set a custom exception handler, which will be called if any of the
1374 Set a custom exception handler, which will be called if any of the
1375 exceptions in exc_tuple occur in the mainloop (specifically, in the
1375 exceptions in exc_tuple occur in the mainloop (specifically, in the
1376 runcode() method.
1376 runcode() method.
1377
1377
1378 Inputs:
1378 Inputs:
1379
1379
1380 - exc_tuple: a *tuple* of valid exceptions to call the defined
1380 - exc_tuple: a *tuple* of valid exceptions to call the defined
1381 handler for. It is very important that you use a tuple, and NOT A
1381 handler for. It is very important that you use a tuple, and NOT A
1382 LIST here, because of the way Python's except statement works. If
1382 LIST here, because of the way Python's except statement works. If
1383 you only want to trap a single exception, use a singleton tuple:
1383 you only want to trap a single exception, use a singleton tuple:
1384
1384
1385 exc_tuple == (MyCustomException,)
1385 exc_tuple == (MyCustomException,)
1386
1386
1387 - handler: this must be defined as a function with the following
1387 - handler: this must be defined as a function with the following
1388 basic interface::
1388 basic interface::
1389
1389
1390 def my_handler(self, etype, value, tb, tb_offset=None)
1390 def my_handler(self, etype, value, tb, tb_offset=None)
1391 ...
1391 ...
1392 # The return value must be
1392 # The return value must be
1393 return structured_traceback
1393 return structured_traceback
1394
1394
1395 This will be made into an instance method (via new.instancemethod)
1395 This will be made into an instance method (via new.instancemethod)
1396 of IPython itself, and it will be called if any of the exceptions
1396 of IPython itself, and it will be called if any of the exceptions
1397 listed in the exc_tuple are caught. If the handler is None, an
1397 listed in the exc_tuple are caught. If the handler is None, an
1398 internal basic one is used, which just prints basic info.
1398 internal basic one is used, which just prints basic info.
1399
1399
1400 WARNING: by putting in your own exception handler into IPython's main
1400 WARNING: by putting in your own exception handler into IPython's main
1401 execution loop, you run a very good chance of nasty crashes. This
1401 execution loop, you run a very good chance of nasty crashes. This
1402 facility should only be used if you really know what you are doing."""
1402 facility should only be used if you really know what you are doing."""
1403
1403
1404 assert type(exc_tuple)==type(()) , \
1404 assert type(exc_tuple)==type(()) , \
1405 "The custom exceptions must be given AS A TUPLE."
1405 "The custom exceptions must be given AS A TUPLE."
1406
1406
1407 def dummy_handler(self,etype,value,tb):
1407 def dummy_handler(self,etype,value,tb):
1408 print '*** Simple custom exception handler ***'
1408 print '*** Simple custom exception handler ***'
1409 print 'Exception type :',etype
1409 print 'Exception type :',etype
1410 print 'Exception value:',value
1410 print 'Exception value:',value
1411 print 'Traceback :',tb
1411 print 'Traceback :',tb
1412 print 'Source code :','\n'.join(self.buffer)
1412 print 'Source code :','\n'.join(self.buffer)
1413
1413
1414 if handler is None: handler = dummy_handler
1414 if handler is None: handler = dummy_handler
1415
1415
1416 self.CustomTB = types.MethodType(handler, self)
1416 self.CustomTB = types.MethodType(handler, self)
1417 self.custom_exceptions = exc_tuple
1417 self.custom_exceptions = exc_tuple
1418
1418
1419 def excepthook(self, etype, value, tb):
1419 def excepthook(self, etype, value, tb):
1420 """One more defense for GUI apps that call sys.excepthook.
1420 """One more defense for GUI apps that call sys.excepthook.
1421
1421
1422 GUI frameworks like wxPython trap exceptions and call
1422 GUI frameworks like wxPython trap exceptions and call
1423 sys.excepthook themselves. I guess this is a feature that
1423 sys.excepthook themselves. I guess this is a feature that
1424 enables them to keep running after exceptions that would
1424 enables them to keep running after exceptions that would
1425 otherwise kill their mainloop. This is a bother for IPython
1425 otherwise kill their mainloop. This is a bother for IPython
1426 which excepts to catch all of the program exceptions with a try:
1426 which excepts to catch all of the program exceptions with a try:
1427 except: statement.
1427 except: statement.
1428
1428
1429 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1429 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1430 any app directly invokes sys.excepthook, it will look to the user like
1430 any app directly invokes sys.excepthook, it will look to the user like
1431 IPython crashed. In order to work around this, we can disable the
1431 IPython crashed. In order to work around this, we can disable the
1432 CrashHandler and replace it with this excepthook instead, which prints a
1432 CrashHandler and replace it with this excepthook instead, which prints a
1433 regular traceback using our InteractiveTB. In this fashion, apps which
1433 regular traceback using our InteractiveTB. In this fashion, apps which
1434 call sys.excepthook will generate a regular-looking exception from
1434 call sys.excepthook will generate a regular-looking exception from
1435 IPython, and the CrashHandler will only be triggered by real IPython
1435 IPython, and the CrashHandler will only be triggered by real IPython
1436 crashes.
1436 crashes.
1437
1437
1438 This hook should be used sparingly, only in places which are not likely
1438 This hook should be used sparingly, only in places which are not likely
1439 to be true IPython errors.
1439 to be true IPython errors.
1440 """
1440 """
1441 self.showtraceback((etype,value,tb),tb_offset=0)
1441 self.showtraceback((etype,value,tb),tb_offset=0)
1442
1442
1443 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1443 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1444 exception_only=False):
1444 exception_only=False):
1445 """Display the exception that just occurred.
1445 """Display the exception that just occurred.
1446
1446
1447 If nothing is known about the exception, this is the method which
1447 If nothing is known about the exception, this is the method which
1448 should be used throughout the code for presenting user tracebacks,
1448 should be used throughout the code for presenting user tracebacks,
1449 rather than directly invoking the InteractiveTB object.
1449 rather than directly invoking the InteractiveTB object.
1450
1450
1451 A specific showsyntaxerror() also exists, but this method can take
1451 A specific showsyntaxerror() also exists, but this method can take
1452 care of calling it if needed, so unless you are explicitly catching a
1452 care of calling it if needed, so unless you are explicitly catching a
1453 SyntaxError exception, don't try to analyze the stack manually and
1453 SyntaxError exception, don't try to analyze the stack manually and
1454 simply call this method."""
1454 simply call this method."""
1455
1455
1456 try:
1456 try:
1457 if exc_tuple is None:
1457 if exc_tuple is None:
1458 etype, value, tb = sys.exc_info()
1458 etype, value, tb = sys.exc_info()
1459 else:
1459 else:
1460 etype, value, tb = exc_tuple
1460 etype, value, tb = exc_tuple
1461
1461
1462 if etype is None:
1462 if etype is None:
1463 if hasattr(sys, 'last_type'):
1463 if hasattr(sys, 'last_type'):
1464 etype, value, tb = sys.last_type, sys.last_value, \
1464 etype, value, tb = sys.last_type, sys.last_value, \
1465 sys.last_traceback
1465 sys.last_traceback
1466 else:
1466 else:
1467 self.write_err('No traceback available to show.\n')
1467 self.write_err('No traceback available to show.\n')
1468 return
1468 return
1469
1469
1470 if etype is SyntaxError:
1470 if etype is SyntaxError:
1471 # Though this won't be called by syntax errors in the input
1471 # Though this won't be called by syntax errors in the input
1472 # line, there may be SyntaxError cases whith imported code.
1472 # line, there may be SyntaxError cases whith imported code.
1473 self.showsyntaxerror(filename)
1473 self.showsyntaxerror(filename)
1474 elif etype is UsageError:
1474 elif etype is UsageError:
1475 print "UsageError:", value
1475 print "UsageError:", value
1476 else:
1476 else:
1477 # WARNING: these variables are somewhat deprecated and not
1477 # WARNING: these variables are somewhat deprecated and not
1478 # necessarily safe to use in a threaded environment, but tools
1478 # necessarily safe to use in a threaded environment, but tools
1479 # like pdb depend on their existence, so let's set them. If we
1479 # like pdb depend on their existence, so let's set them. If we
1480 # find problems in the field, we'll need to revisit their use.
1480 # find problems in the field, we'll need to revisit their use.
1481 sys.last_type = etype
1481 sys.last_type = etype
1482 sys.last_value = value
1482 sys.last_value = value
1483 sys.last_traceback = tb
1483 sys.last_traceback = tb
1484
1484
1485 if etype in self.custom_exceptions:
1485 if etype in self.custom_exceptions:
1486 # FIXME: Old custom traceback objects may just return a
1486 # FIXME: Old custom traceback objects may just return a
1487 # string, in that case we just put it into a list
1487 # string, in that case we just put it into a list
1488 stb = self.CustomTB(etype, value, tb, tb_offset)
1488 stb = self.CustomTB(etype, value, tb, tb_offset)
1489 if isinstance(ctb, basestring):
1489 if isinstance(ctb, basestring):
1490 stb = [stb]
1490 stb = [stb]
1491 else:
1491 else:
1492 if exception_only:
1492 if exception_only:
1493 stb = ['An exception has occurred, use %tb to see '
1493 stb = ['An exception has occurred, use %tb to see '
1494 'the full traceback.\n']
1494 'the full traceback.\n']
1495 stb.extend(self.InteractiveTB.get_exception_only(etype,
1495 stb.extend(self.InteractiveTB.get_exception_only(etype,
1496 value))
1496 value))
1497 else:
1497 else:
1498 stb = self.InteractiveTB.structured_traceback(etype,
1498 stb = self.InteractiveTB.structured_traceback(etype,
1499 value, tb, tb_offset=tb_offset)
1499 value, tb, tb_offset=tb_offset)
1500 # FIXME: the pdb calling should be done by us, not by
1500 # FIXME: the pdb calling should be done by us, not by
1501 # the code computing the traceback.
1501 # the code computing the traceback.
1502 if self.InteractiveTB.call_pdb:
1502 if self.InteractiveTB.call_pdb:
1503 # pdb mucks up readline, fix it back
1503 # pdb mucks up readline, fix it back
1504 self.set_readline_completer()
1504 self.set_readline_completer()
1505
1505
1506 # Actually show the traceback
1506 # Actually show the traceback
1507 self._showtraceback(etype, value, stb)
1507 self._showtraceback(etype, value, stb)
1508
1508
1509 except KeyboardInterrupt:
1509 except KeyboardInterrupt:
1510 self.write_err("\nKeyboardInterrupt\n")
1510 self.write_err("\nKeyboardInterrupt\n")
1511
1511
1512 def _showtraceback(self, etype, evalue, stb):
1512 def _showtraceback(self, etype, evalue, stb):
1513 """Actually show a traceback.
1513 """Actually show a traceback.
1514
1514
1515 Subclasses may override this method to put the traceback on a different
1515 Subclasses may override this method to put the traceback on a different
1516 place, like a side channel.
1516 place, like a side channel.
1517 """
1517 """
1518 print >> io.Term.cout, self.InteractiveTB.stb2text(stb)
1518 print >> io.Term.cout, self.InteractiveTB.stb2text(stb)
1519
1519
1520 def showsyntaxerror(self, filename=None):
1520 def showsyntaxerror(self, filename=None):
1521 """Display the syntax error that just occurred.
1521 """Display the syntax error that just occurred.
1522
1522
1523 This doesn't display a stack trace because there isn't one.
1523 This doesn't display a stack trace because there isn't one.
1524
1524
1525 If a filename is given, it is stuffed in the exception instead
1525 If a filename is given, it is stuffed in the exception instead
1526 of what was there before (because Python's parser always uses
1526 of what was there before (because Python's parser always uses
1527 "<string>" when reading from a string).
1527 "<string>" when reading from a string).
1528 """
1528 """
1529 etype, value, last_traceback = sys.exc_info()
1529 etype, value, last_traceback = sys.exc_info()
1530
1530
1531 # See note about these variables in showtraceback() above
1531 # See note about these variables in showtraceback() above
1532 sys.last_type = etype
1532 sys.last_type = etype
1533 sys.last_value = value
1533 sys.last_value = value
1534 sys.last_traceback = last_traceback
1534 sys.last_traceback = last_traceback
1535
1535
1536 if filename and etype is SyntaxError:
1536 if filename and etype is SyntaxError:
1537 # Work hard to stuff the correct filename in the exception
1537 # Work hard to stuff the correct filename in the exception
1538 try:
1538 try:
1539 msg, (dummy_filename, lineno, offset, line) = value
1539 msg, (dummy_filename, lineno, offset, line) = value
1540 except:
1540 except:
1541 # Not the format we expect; leave it alone
1541 # Not the format we expect; leave it alone
1542 pass
1542 pass
1543 else:
1543 else:
1544 # Stuff in the right filename
1544 # Stuff in the right filename
1545 try:
1545 try:
1546 # Assume SyntaxError is a class exception
1546 # Assume SyntaxError is a class exception
1547 value = SyntaxError(msg, (filename, lineno, offset, line))
1547 value = SyntaxError(msg, (filename, lineno, offset, line))
1548 except:
1548 except:
1549 # If that failed, assume SyntaxError is a string
1549 # If that failed, assume SyntaxError is a string
1550 value = msg, (filename, lineno, offset, line)
1550 value = msg, (filename, lineno, offset, line)
1551 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1551 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1552 self._showtraceback(etype, value, stb)
1552 self._showtraceback(etype, value, stb)
1553
1553
1554 #-------------------------------------------------------------------------
1554 #-------------------------------------------------------------------------
1555 # Things related to readline
1555 # Things related to readline
1556 #-------------------------------------------------------------------------
1556 #-------------------------------------------------------------------------
1557
1557
1558 def init_readline(self):
1558 def init_readline(self):
1559 """Command history completion/saving/reloading."""
1559 """Command history completion/saving/reloading."""
1560
1560
1561 if self.readline_use:
1561 if self.readline_use:
1562 import IPython.utils.rlineimpl as readline
1562 import IPython.utils.rlineimpl as readline
1563
1563
1564 self.rl_next_input = None
1564 self.rl_next_input = None
1565 self.rl_do_indent = False
1565 self.rl_do_indent = False
1566
1566
1567 if not self.readline_use or not readline.have_readline:
1567 if not self.readline_use or not readline.have_readline:
1568 self.has_readline = False
1568 self.has_readline = False
1569 self.readline = None
1569 self.readline = None
1570 # Set a number of methods that depend on readline to be no-op
1570 # Set a number of methods that depend on readline to be no-op
1571 self.savehist = no_op
1571 self.savehist = no_op
1572 self.reloadhist = no_op
1572 self.reloadhist = no_op
1573 self.set_readline_completer = no_op
1573 self.set_readline_completer = no_op
1574 self.set_custom_completer = no_op
1574 self.set_custom_completer = no_op
1575 self.set_completer_frame = no_op
1575 self.set_completer_frame = no_op
1576 warn('Readline services not available or not loaded.')
1576 warn('Readline services not available or not loaded.')
1577 else:
1577 else:
1578 self.has_readline = True
1578 self.has_readline = True
1579 self.readline = readline
1579 self.readline = readline
1580 sys.modules['readline'] = readline
1580 sys.modules['readline'] = readline
1581
1581
1582 # Platform-specific configuration
1582 # Platform-specific configuration
1583 if os.name == 'nt':
1583 if os.name == 'nt':
1584 # FIXME - check with Frederick to see if we can harmonize
1584 # FIXME - check with Frederick to see if we can harmonize
1585 # naming conventions with pyreadline to avoid this
1585 # naming conventions with pyreadline to avoid this
1586 # platform-dependent check
1586 # platform-dependent check
1587 self.readline_startup_hook = readline.set_pre_input_hook
1587 self.readline_startup_hook = readline.set_pre_input_hook
1588 else:
1588 else:
1589 self.readline_startup_hook = readline.set_startup_hook
1589 self.readline_startup_hook = readline.set_startup_hook
1590
1590
1591 # Load user's initrc file (readline config)
1591 # Load user's initrc file (readline config)
1592 # Or if libedit is used, load editrc.
1592 # Or if libedit is used, load editrc.
1593 inputrc_name = os.environ.get('INPUTRC')
1593 inputrc_name = os.environ.get('INPUTRC')
1594 if inputrc_name is None:
1594 if inputrc_name is None:
1595 home_dir = get_home_dir()
1595 home_dir = get_home_dir()
1596 if home_dir is not None:
1596 if home_dir is not None:
1597 inputrc_name = '.inputrc'
1597 inputrc_name = '.inputrc'
1598 if readline.uses_libedit:
1598 if readline.uses_libedit:
1599 inputrc_name = '.editrc'
1599 inputrc_name = '.editrc'
1600 inputrc_name = os.path.join(home_dir, inputrc_name)
1600 inputrc_name = os.path.join(home_dir, inputrc_name)
1601 if os.path.isfile(inputrc_name):
1601 if os.path.isfile(inputrc_name):
1602 try:
1602 try:
1603 readline.read_init_file(inputrc_name)
1603 readline.read_init_file(inputrc_name)
1604 except:
1604 except:
1605 warn('Problems reading readline initialization file <%s>'
1605 warn('Problems reading readline initialization file <%s>'
1606 % inputrc_name)
1606 % inputrc_name)
1607
1607
1608 # Configure readline according to user's prefs
1608 # Configure readline according to user's prefs
1609 # This is only done if GNU readline is being used. If libedit
1609 # This is only done if GNU readline is being used. If libedit
1610 # is being used (as on Leopard) the readline config is
1610 # is being used (as on Leopard) the readline config is
1611 # not run as the syntax for libedit is different.
1611 # not run as the syntax for libedit is different.
1612 if not readline.uses_libedit:
1612 if not readline.uses_libedit:
1613 for rlcommand in self.readline_parse_and_bind:
1613 for rlcommand in self.readline_parse_and_bind:
1614 #print "loading rl:",rlcommand # dbg
1614 #print "loading rl:",rlcommand # dbg
1615 readline.parse_and_bind(rlcommand)
1615 readline.parse_and_bind(rlcommand)
1616
1616
1617 # Remove some chars from the delimiters list. If we encounter
1617 # Remove some chars from the delimiters list. If we encounter
1618 # unicode chars, discard them.
1618 # unicode chars, discard them.
1619 delims = readline.get_completer_delims().encode("ascii", "ignore")
1619 delims = readline.get_completer_delims().encode("ascii", "ignore")
1620 delims = delims.translate(string._idmap,
1620 delims = delims.translate(string._idmap,
1621 self.readline_remove_delims)
1621 self.readline_remove_delims)
1622 delims = delims.replace(ESC_MAGIC, '')
1622 delims = delims.replace(ESC_MAGIC, '')
1623 readline.set_completer_delims(delims)
1623 readline.set_completer_delims(delims)
1624 # otherwise we end up with a monster history after a while:
1624 # otherwise we end up with a monster history after a while:
1625 readline.set_history_length(1000)
1625 readline.set_history_length(1000)
1626 try:
1626 try:
1627 #print '*** Reading readline history' # dbg
1627 #print '*** Reading readline history' # dbg
1628 readline.read_history_file(self.histfile)
1628 readline.read_history_file(self.histfile)
1629 except IOError:
1629 except IOError:
1630 pass # It doesn't exist yet.
1630 pass # It doesn't exist yet.
1631
1631
1632 # If we have readline, we want our history saved upon ipython
1632 # If we have readline, we want our history saved upon ipython
1633 # exiting.
1633 # exiting.
1634 atexit.register(self.savehist)
1634 atexit.register(self.savehist)
1635
1635
1636 # Configure auto-indent for all platforms
1636 # Configure auto-indent for all platforms
1637 self.set_autoindent(self.autoindent)
1637 self.set_autoindent(self.autoindent)
1638
1638
1639 def set_next_input(self, s):
1639 def set_next_input(self, s):
1640 """ Sets the 'default' input string for the next command line.
1640 """ Sets the 'default' input string for the next command line.
1641
1641
1642 Requires readline.
1642 Requires readline.
1643
1643
1644 Example:
1644 Example:
1645
1645
1646 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1646 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1647 [D:\ipython]|2> Hello Word_ # cursor is here
1647 [D:\ipython]|2> Hello Word_ # cursor is here
1648 """
1648 """
1649
1649
1650 self.rl_next_input = s
1650 self.rl_next_input = s
1651
1651
1652 # Maybe move this to the terminal subclass?
1652 # Maybe move this to the terminal subclass?
1653 def pre_readline(self):
1653 def pre_readline(self):
1654 """readline hook to be used at the start of each line.
1654 """readline hook to be used at the start of each line.
1655
1655
1656 Currently it handles auto-indent only."""
1656 Currently it handles auto-indent only."""
1657
1657
1658 if self.rl_do_indent:
1658 if self.rl_do_indent:
1659 self.readline.insert_text(self._indent_current_str())
1659 self.readline.insert_text(self._indent_current_str())
1660 if self.rl_next_input is not None:
1660 if self.rl_next_input is not None:
1661 self.readline.insert_text(self.rl_next_input)
1661 self.readline.insert_text(self.rl_next_input)
1662 self.rl_next_input = None
1662 self.rl_next_input = None
1663
1663
1664 def _indent_current_str(self):
1664 def _indent_current_str(self):
1665 """return the current level of indentation as a string"""
1665 """return the current level of indentation as a string"""
1666 return self.indent_current_nsp * ' '
1666 return self.indent_current_nsp * ' '
1667
1667
1668 #-------------------------------------------------------------------------
1668 #-------------------------------------------------------------------------
1669 # Things related to text completion
1669 # Things related to text completion
1670 #-------------------------------------------------------------------------
1670 #-------------------------------------------------------------------------
1671
1671
1672 def init_completer(self):
1672 def init_completer(self):
1673 """Initialize the completion machinery.
1673 """Initialize the completion machinery.
1674
1674
1675 This creates completion machinery that can be used by client code,
1675 This creates completion machinery that can be used by client code,
1676 either interactively in-process (typically triggered by the readline
1676 either interactively in-process (typically triggered by the readline
1677 library), programatically (such as in test suites) or out-of-prcess
1677 library), programatically (such as in test suites) or out-of-prcess
1678 (typically over the network by remote frontends).
1678 (typically over the network by remote frontends).
1679 """
1679 """
1680 from IPython.core.completer import IPCompleter
1680 from IPython.core.completer import IPCompleter
1681 from IPython.core.completerlib import (module_completer,
1681 from IPython.core.completerlib import (module_completer,
1682 magic_run_completer, cd_completer)
1682 magic_run_completer, cd_completer)
1683
1683
1684 self.Completer = IPCompleter(self,
1684 self.Completer = IPCompleter(self,
1685 self.user_ns,
1685 self.user_ns,
1686 self.user_global_ns,
1686 self.user_global_ns,
1687 self.readline_omit__names,
1687 self.readline_omit__names,
1688 self.alias_manager.alias_table,
1688 self.alias_manager.alias_table,
1689 self.has_readline)
1689 self.has_readline)
1690
1690
1691 # Add custom completers to the basic ones built into IPCompleter
1691 # Add custom completers to the basic ones built into IPCompleter
1692 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1692 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1693 self.strdispatchers['complete_command'] = sdisp
1693 self.strdispatchers['complete_command'] = sdisp
1694 self.Completer.custom_completers = sdisp
1694 self.Completer.custom_completers = sdisp
1695
1695
1696 self.set_hook('complete_command', module_completer, str_key = 'import')
1696 self.set_hook('complete_command', module_completer, str_key = 'import')
1697 self.set_hook('complete_command', module_completer, str_key = 'from')
1697 self.set_hook('complete_command', module_completer, str_key = 'from')
1698 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1698 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1699 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1699 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1700
1700
1701 # Only configure readline if we truly are using readline. IPython can
1701 # Only configure readline if we truly are using readline. IPython can
1702 # do tab-completion over the network, in GUIs, etc, where readline
1702 # do tab-completion over the network, in GUIs, etc, where readline
1703 # itself may be absent
1703 # itself may be absent
1704 if self.has_readline:
1704 if self.has_readline:
1705 self.set_readline_completer()
1705 self.set_readline_completer()
1706
1706
1707 def complete(self, text, line=None, cursor_pos=None):
1707 def complete(self, text, line=None, cursor_pos=None):
1708 """Return the completed text and a list of completions.
1708 """Return the completed text and a list of completions.
1709
1709
1710 Parameters
1710 Parameters
1711 ----------
1711 ----------
1712
1712
1713 text : string
1713 text : string
1714 A string of text to be completed on. It can be given as empty and
1714 A string of text to be completed on. It can be given as empty and
1715 instead a line/position pair are given. In this case, the
1715 instead a line/position pair are given. In this case, the
1716 completer itself will split the line like readline does.
1716 completer itself will split the line like readline does.
1717
1717
1718 line : string, optional
1718 line : string, optional
1719 The complete line that text is part of.
1719 The complete line that text is part of.
1720
1720
1721 cursor_pos : int, optional
1721 cursor_pos : int, optional
1722 The position of the cursor on the input line.
1722 The position of the cursor on the input line.
1723
1723
1724 Returns
1724 Returns
1725 -------
1725 -------
1726 text : string
1726 text : string
1727 The actual text that was completed.
1727 The actual text that was completed.
1728
1728
1729 matches : list
1729 matches : list
1730 A sorted list with all possible completions.
1730 A sorted list with all possible completions.
1731
1731
1732 The optional arguments allow the completion to take more context into
1732 The optional arguments allow the completion to take more context into
1733 account, and are part of the low-level completion API.
1733 account, and are part of the low-level completion API.
1734
1734
1735 This is a wrapper around the completion mechanism, similar to what
1735 This is a wrapper around the completion mechanism, similar to what
1736 readline does at the command line when the TAB key is hit. By
1736 readline does at the command line when the TAB key is hit. By
1737 exposing it as a method, it can be used by other non-readline
1737 exposing it as a method, it can be used by other non-readline
1738 environments (such as GUIs) for text completion.
1738 environments (such as GUIs) for text completion.
1739
1739
1740 Simple usage example:
1740 Simple usage example:
1741
1741
1742 In [1]: x = 'hello'
1742 In [1]: x = 'hello'
1743
1743
1744 In [2]: _ip.complete('x.l')
1744 In [2]: _ip.complete('x.l')
1745 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
1745 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
1746 """
1746 """
1747
1747
1748 # Inject names into __builtin__ so we can complete on the added names.
1748 # Inject names into __builtin__ so we can complete on the added names.
1749 with self.builtin_trap:
1749 with self.builtin_trap:
1750 return self.Completer.complete(text, line, cursor_pos)
1750 return self.Completer.complete(text, line, cursor_pos)
1751
1751
1752 def set_custom_completer(self, completer, pos=0):
1752 def set_custom_completer(self, completer, pos=0):
1753 """Adds a new custom completer function.
1753 """Adds a new custom completer function.
1754
1754
1755 The position argument (defaults to 0) is the index in the completers
1755 The position argument (defaults to 0) is the index in the completers
1756 list where you want the completer to be inserted."""
1756 list where you want the completer to be inserted."""
1757
1757
1758 newcomp = types.MethodType(completer, self.Completer)
1758 newcomp = types.MethodType(completer, self.Completer)
1759 self.Completer.matchers.insert(pos,newcomp)
1759 self.Completer.matchers.insert(pos,newcomp)
1760
1760
1761 def set_readline_completer(self):
1761 def set_readline_completer(self):
1762 """Reset readline's completer to be our own."""
1762 """Reset readline's completer to be our own."""
1763 self.readline.set_completer(self.Completer.rlcomplete)
1763 self.readline.set_completer(self.Completer.rlcomplete)
1764
1764
1765 def set_completer_frame(self, frame=None):
1765 def set_completer_frame(self, frame=None):
1766 """Set the frame of the completer."""
1766 """Set the frame of the completer."""
1767 if frame:
1767 if frame:
1768 self.Completer.namespace = frame.f_locals
1768 self.Completer.namespace = frame.f_locals
1769 self.Completer.global_namespace = frame.f_globals
1769 self.Completer.global_namespace = frame.f_globals
1770 else:
1770 else:
1771 self.Completer.namespace = self.user_ns
1771 self.Completer.namespace = self.user_ns
1772 self.Completer.global_namespace = self.user_global_ns
1772 self.Completer.global_namespace = self.user_global_ns
1773
1773
1774 #-------------------------------------------------------------------------
1774 #-------------------------------------------------------------------------
1775 # Things related to magics
1775 # Things related to magics
1776 #-------------------------------------------------------------------------
1776 #-------------------------------------------------------------------------
1777
1777
1778 def init_magics(self):
1778 def init_magics(self):
1779 # FIXME: Move the color initialization to the DisplayHook, which
1779 # FIXME: Move the color initialization to the DisplayHook, which
1780 # should be split into a prompt manager and displayhook. We probably
1780 # should be split into a prompt manager and displayhook. We probably
1781 # even need a centralize colors management object.
1781 # even need a centralize colors management object.
1782 self.magic_colors(self.colors)
1782 self.magic_colors(self.colors)
1783 # History was moved to a separate module
1783 # History was moved to a separate module
1784 from . import history
1784 from . import history
1785 history.init_ipython(self)
1785 history.init_ipython(self)
1786
1786
1787 def magic(self,arg_s):
1787 def magic(self,arg_s):
1788 """Call a magic function by name.
1788 """Call a magic function by name.
1789
1789
1790 Input: a string containing the name of the magic function to call and
1790 Input: a string containing the name of the magic function to call and
1791 any additional arguments to be passed to the magic.
1791 any additional arguments to be passed to the magic.
1792
1792
1793 magic('name -opt foo bar') is equivalent to typing at the ipython
1793 magic('name -opt foo bar') is equivalent to typing at the ipython
1794 prompt:
1794 prompt:
1795
1795
1796 In[1]: %name -opt foo bar
1796 In[1]: %name -opt foo bar
1797
1797
1798 To call a magic without arguments, simply use magic('name').
1798 To call a magic without arguments, simply use magic('name').
1799
1799
1800 This provides a proper Python function to call IPython's magics in any
1800 This provides a proper Python function to call IPython's magics in any
1801 valid Python code you can type at the interpreter, including loops and
1801 valid Python code you can type at the interpreter, including loops and
1802 compound statements.
1802 compound statements.
1803 """
1803 """
1804 args = arg_s.split(' ',1)
1804 args = arg_s.split(' ',1)
1805 magic_name = args[0]
1805 magic_name = args[0]
1806 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1806 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1807
1807
1808 try:
1808 try:
1809 magic_args = args[1]
1809 magic_args = args[1]
1810 except IndexError:
1810 except IndexError:
1811 magic_args = ''
1811 magic_args = ''
1812 fn = getattr(self,'magic_'+magic_name,None)
1812 fn = getattr(self,'magic_'+magic_name,None)
1813 if fn is None:
1813 if fn is None:
1814 error("Magic function `%s` not found." % magic_name)
1814 error("Magic function `%s` not found." % magic_name)
1815 else:
1815 else:
1816 magic_args = self.var_expand(magic_args,1)
1816 magic_args = self.var_expand(magic_args,1)
1817 with nested(self.builtin_trap,):
1817 with nested(self.builtin_trap,):
1818 result = fn(magic_args)
1818 result = fn(magic_args)
1819 return result
1819 return result
1820
1820
1821 def define_magic(self, magicname, func):
1821 def define_magic(self, magicname, func):
1822 """Expose own function as magic function for ipython
1822 """Expose own function as magic function for ipython
1823
1823
1824 def foo_impl(self,parameter_s=''):
1824 def foo_impl(self,parameter_s=''):
1825 'My very own magic!. (Use docstrings, IPython reads them).'
1825 'My very own magic!. (Use docstrings, IPython reads them).'
1826 print 'Magic function. Passed parameter is between < >:'
1826 print 'Magic function. Passed parameter is between < >:'
1827 print '<%s>' % parameter_s
1827 print '<%s>' % parameter_s
1828 print 'The self object is:',self
1828 print 'The self object is:',self
1829 newcomp = types.MethodType(completer, self.Completer)
1829 newcomp = types.MethodType(completer, self.Completer)
1830 self.define_magic('foo',foo_impl)
1830 self.define_magic('foo',foo_impl)
1831 """
1831 """
1832
1832
1833 im = types.MethodType(func, self)
1833 im = types.MethodType(func, self)
1834 old = getattr(self, "magic_" + magicname, None)
1834 old = getattr(self, "magic_" + magicname, None)
1835 setattr(self, "magic_" + magicname, im)
1835 setattr(self, "magic_" + magicname, im)
1836 return old
1836 return old
1837
1837
1838 #-------------------------------------------------------------------------
1838 #-------------------------------------------------------------------------
1839 # Things related to macros
1839 # Things related to macros
1840 #-------------------------------------------------------------------------
1840 #-------------------------------------------------------------------------
1841
1841
1842 def define_macro(self, name, themacro):
1842 def define_macro(self, name, themacro):
1843 """Define a new macro
1843 """Define a new macro
1844
1844
1845 Parameters
1845 Parameters
1846 ----------
1846 ----------
1847 name : str
1847 name : str
1848 The name of the macro.
1848 The name of the macro.
1849 themacro : str or Macro
1849 themacro : str or Macro
1850 The action to do upon invoking the macro. If a string, a new
1850 The action to do upon invoking the macro. If a string, a new
1851 Macro object is created by passing the string to it.
1851 Macro object is created by passing the string to it.
1852 """
1852 """
1853
1853
1854 from IPython.core import macro
1854 from IPython.core import macro
1855
1855
1856 if isinstance(themacro, basestring):
1856 if isinstance(themacro, basestring):
1857 themacro = macro.Macro(themacro)
1857 themacro = macro.Macro(themacro)
1858 if not isinstance(themacro, macro.Macro):
1858 if not isinstance(themacro, macro.Macro):
1859 raise ValueError('A macro must be a string or a Macro instance.')
1859 raise ValueError('A macro must be a string or a Macro instance.')
1860 self.user_ns[name] = themacro
1860 self.user_ns[name] = themacro
1861
1861
1862 #-------------------------------------------------------------------------
1862 #-------------------------------------------------------------------------
1863 # Things related to the running of system commands
1863 # Things related to the running of system commands
1864 #-------------------------------------------------------------------------
1864 #-------------------------------------------------------------------------
1865
1865
1866 def system(self, cmd):
1866 def system(self, cmd):
1867 """Call the given cmd in a subprocess.
1867 """Call the given cmd in a subprocess.
1868
1868
1869 Parameters
1869 Parameters
1870 ----------
1870 ----------
1871 cmd : str
1871 cmd : str
1872 Command to execute (can not end in '&', as bacground processes are
1872 Command to execute (can not end in '&', as bacground processes are
1873 not supported.
1873 not supported.
1874 """
1874 """
1875 # We do not support backgrounding processes because we either use
1875 # We do not support backgrounding processes because we either use
1876 # pexpect or pipes to read from. Users can always just call
1876 # pexpect or pipes to read from. Users can always just call
1877 # os.system() if they really want a background process.
1877 # os.system() if they really want a background process.
1878 if cmd.endswith('&'):
1878 if cmd.endswith('&'):
1879 raise OSError("Background processes not supported.")
1879 raise OSError("Background processes not supported.")
1880
1880
1881 return system(self.var_expand(cmd, depth=2))
1881 return system(self.var_expand(cmd, depth=2))
1882
1882
1883 def getoutput(self, cmd, split=True):
1883 def getoutput(self, cmd, split=True):
1884 """Get output (possibly including stderr) from a subprocess.
1884 """Get output (possibly including stderr) from a subprocess.
1885
1885
1886 Parameters
1886 Parameters
1887 ----------
1887 ----------
1888 cmd : str
1888 cmd : str
1889 Command to execute (can not end in '&', as background processes are
1889 Command to execute (can not end in '&', as background processes are
1890 not supported.
1890 not supported.
1891 split : bool, optional
1891 split : bool, optional
1892
1892
1893 If True, split the output into an IPython SList. Otherwise, an
1893 If True, split the output into an IPython SList. Otherwise, an
1894 IPython LSString is returned. These are objects similar to normal
1894 IPython LSString is returned. These are objects similar to normal
1895 lists and strings, with a few convenience attributes for easier
1895 lists and strings, with a few convenience attributes for easier
1896 manipulation of line-based output. You can use '?' on them for
1896 manipulation of line-based output. You can use '?' on them for
1897 details.
1897 details.
1898 """
1898 """
1899 if cmd.endswith('&'):
1899 if cmd.endswith('&'):
1900 raise OSError("Background processes not supported.")
1900 raise OSError("Background processes not supported.")
1901 out = getoutput(self.var_expand(cmd, depth=2))
1901 out = getoutput(self.var_expand(cmd, depth=2))
1902 if split:
1902 if split:
1903 out = SList(out.splitlines())
1903 out = SList(out.splitlines())
1904 else:
1904 else:
1905 out = LSString(out)
1905 out = LSString(out)
1906 return out
1906 return out
1907
1907
1908 #-------------------------------------------------------------------------
1908 #-------------------------------------------------------------------------
1909 # Things related to aliases
1909 # Things related to aliases
1910 #-------------------------------------------------------------------------
1910 #-------------------------------------------------------------------------
1911
1911
1912 def init_alias(self):
1912 def init_alias(self):
1913 self.alias_manager = AliasManager(shell=self, config=self.config)
1913 self.alias_manager = AliasManager(shell=self, config=self.config)
1914 self.ns_table['alias'] = self.alias_manager.alias_table,
1914 self.ns_table['alias'] = self.alias_manager.alias_table,
1915
1915
1916 #-------------------------------------------------------------------------
1916 #-------------------------------------------------------------------------
1917 # Things related to extensions and plugins
1917 # Things related to extensions and plugins
1918 #-------------------------------------------------------------------------
1918 #-------------------------------------------------------------------------
1919
1919
1920 def init_extension_manager(self):
1920 def init_extension_manager(self):
1921 self.extension_manager = ExtensionManager(shell=self, config=self.config)
1921 self.extension_manager = ExtensionManager(shell=self, config=self.config)
1922
1922
1923 def init_plugin_manager(self):
1923 def init_plugin_manager(self):
1924 self.plugin_manager = PluginManager(config=self.config)
1924 self.plugin_manager = PluginManager(config=self.config)
1925
1925
1926 #-------------------------------------------------------------------------
1926 #-------------------------------------------------------------------------
1927 # Things related to payloads
1927 # Things related to payloads
1928 #-------------------------------------------------------------------------
1928 #-------------------------------------------------------------------------
1929
1929
1930 def init_payload(self):
1930 def init_payload(self):
1931 self.payload_manager = PayloadManager(config=self.config)
1931 self.payload_manager = PayloadManager(config=self.config)
1932
1932
1933 #-------------------------------------------------------------------------
1933 #-------------------------------------------------------------------------
1934 # Things related to the prefilter
1934 # Things related to the prefilter
1935 #-------------------------------------------------------------------------
1935 #-------------------------------------------------------------------------
1936
1936
1937 def init_prefilter(self):
1937 def init_prefilter(self):
1938 self.prefilter_manager = PrefilterManager(shell=self, config=self.config)
1938 self.prefilter_manager = PrefilterManager(shell=self, config=self.config)
1939 # Ultimately this will be refactored in the new interpreter code, but
1939 # Ultimately this will be refactored in the new interpreter code, but
1940 # for now, we should expose the main prefilter method (there's legacy
1940 # for now, we should expose the main prefilter method (there's legacy
1941 # code out there that may rely on this).
1941 # code out there that may rely on this).
1942 self.prefilter = self.prefilter_manager.prefilter_lines
1942 self.prefilter = self.prefilter_manager.prefilter_lines
1943
1943
1944
1944
1945 def auto_rewrite_input(self, cmd):
1945 def auto_rewrite_input(self, cmd):
1946 """Print to the screen the rewritten form of the user's command.
1946 """Print to the screen the rewritten form of the user's command.
1947
1947
1948 This shows visual feedback by rewriting input lines that cause
1948 This shows visual feedback by rewriting input lines that cause
1949 automatic calling to kick in, like::
1949 automatic calling to kick in, like::
1950
1950
1951 /f x
1951 /f x
1952
1952
1953 into::
1953 into::
1954
1954
1955 ------> f(x)
1955 ------> f(x)
1956
1956
1957 after the user's input prompt. This helps the user understand that the
1957 after the user's input prompt. This helps the user understand that the
1958 input line was transformed automatically by IPython.
1958 input line was transformed automatically by IPython.
1959 """
1959 """
1960 rw = self.displayhook.prompt1.auto_rewrite() + cmd
1960 rw = self.displayhook.prompt1.auto_rewrite() + cmd
1961
1961
1962 try:
1962 try:
1963 # plain ascii works better w/ pyreadline, on some machines, so
1963 # plain ascii works better w/ pyreadline, on some machines, so
1964 # we use it and only print uncolored rewrite if we have unicode
1964 # we use it and only print uncolored rewrite if we have unicode
1965 rw = str(rw)
1965 rw = str(rw)
1966 print >> IPython.utils.io.Term.cout, rw
1966 print >> IPython.utils.io.Term.cout, rw
1967 except UnicodeEncodeError:
1967 except UnicodeEncodeError:
1968 print "------> " + cmd
1968 print "------> " + cmd
1969
1969
1970 #-------------------------------------------------------------------------
1970 #-------------------------------------------------------------------------
1971 # Things related to extracting values/expressions from kernel and user_ns
1971 # Things related to extracting values/expressions from kernel and user_ns
1972 #-------------------------------------------------------------------------
1972 #-------------------------------------------------------------------------
1973
1973
1974 def _simple_error(self):
1974 def _simple_error(self):
1975 etype, value = sys.exc_info()[:2]
1975 etype, value = sys.exc_info()[:2]
1976 return u'[ERROR] {e.__name__}: {v}'.format(e=etype, v=value)
1976 return u'[ERROR] {e.__name__}: {v}'.format(e=etype, v=value)
1977
1977
1978 def user_variables(self, names):
1978 def user_variables(self, names):
1979 """Get a list of variable names from the user's namespace.
1979 """Get a list of variable names from the user's namespace.
1980
1980
1981 Parameters
1981 Parameters
1982 ----------
1982 ----------
1983 names : list of strings
1983 names : list of strings
1984 A list of names of variables to be read from the user namespace.
1984 A list of names of variables to be read from the user namespace.
1985
1985
1986 Returns
1986 Returns
1987 -------
1987 -------
1988 A dict, keyed by the input names and with the repr() of each value.
1988 A dict, keyed by the input names and with the repr() of each value.
1989 """
1989 """
1990 out = {}
1990 out = {}
1991 user_ns = self.user_ns
1991 user_ns = self.user_ns
1992 for varname in names:
1992 for varname in names:
1993 try:
1993 try:
1994 value = repr(user_ns[varname])
1994 value = repr(user_ns[varname])
1995 except:
1995 except:
1996 value = self._simple_error()
1996 value = self._simple_error()
1997 out[varname] = value
1997 out[varname] = value
1998 return out
1998 return out
1999
1999
2000 def user_expressions(self, expressions):
2000 def user_expressions(self, expressions):
2001 """Evaluate a dict of expressions in the user's namespace.
2001 """Evaluate a dict of expressions in the user's namespace.
2002
2002
2003 Parameters
2003 Parameters
2004 ----------
2004 ----------
2005 expressions : dict
2005 expressions : dict
2006 A dict with string keys and string values. The expression values
2006 A dict with string keys and string values. The expression values
2007 should be valid Python expressions, each of which will be evaluated
2007 should be valid Python expressions, each of which will be evaluated
2008 in the user namespace.
2008 in the user namespace.
2009
2009
2010 Returns
2010 Returns
2011 -------
2011 -------
2012 A dict, keyed like the input expressions dict, with the repr() of each
2012 A dict, keyed like the input expressions dict, with the repr() of each
2013 value.
2013 value.
2014 """
2014 """
2015 out = {}
2015 out = {}
2016 user_ns = self.user_ns
2016 user_ns = self.user_ns
2017 global_ns = self.user_global_ns
2017 global_ns = self.user_global_ns
2018 for key, expr in expressions.iteritems():
2018 for key, expr in expressions.iteritems():
2019 try:
2019 try:
2020 value = repr(eval(expr, global_ns, user_ns))
2020 value = repr(eval(expr, global_ns, user_ns))
2021 except:
2021 except:
2022 value = self._simple_error()
2022 value = self._simple_error()
2023 out[key] = value
2023 out[key] = value
2024 return out
2024 return out
2025
2025
2026 #-------------------------------------------------------------------------
2026 #-------------------------------------------------------------------------
2027 # Things related to the running of code
2027 # Things related to the running of code
2028 #-------------------------------------------------------------------------
2028 #-------------------------------------------------------------------------
2029
2029
2030 def ex(self, cmd):
2030 def ex(self, cmd):
2031 """Execute a normal python statement in user namespace."""
2031 """Execute a normal python statement in user namespace."""
2032 with nested(self.builtin_trap,):
2032 with nested(self.builtin_trap,):
2033 exec cmd in self.user_global_ns, self.user_ns
2033 exec cmd in self.user_global_ns, self.user_ns
2034
2034
2035 def ev(self, expr):
2035 def ev(self, expr):
2036 """Evaluate python expression expr in user namespace.
2036 """Evaluate python expression expr in user namespace.
2037
2037
2038 Returns the result of evaluation
2038 Returns the result of evaluation
2039 """
2039 """
2040 with nested(self.builtin_trap,):
2040 with nested(self.builtin_trap,):
2041 return eval(expr, self.user_global_ns, self.user_ns)
2041 return eval(expr, self.user_global_ns, self.user_ns)
2042
2042
2043 def safe_execfile(self, fname, *where, **kw):
2043 def safe_execfile(self, fname, *where, **kw):
2044 """A safe version of the builtin execfile().
2044 """A safe version of the builtin execfile().
2045
2045
2046 This version will never throw an exception, but instead print
2046 This version will never throw an exception, but instead print
2047 helpful error messages to the screen. This only works on pure
2047 helpful error messages to the screen. This only works on pure
2048 Python files with the .py extension.
2048 Python files with the .py extension.
2049
2049
2050 Parameters
2050 Parameters
2051 ----------
2051 ----------
2052 fname : string
2052 fname : string
2053 The name of the file to be executed.
2053 The name of the file to be executed.
2054 where : tuple
2054 where : tuple
2055 One or two namespaces, passed to execfile() as (globals,locals).
2055 One or two namespaces, passed to execfile() as (globals,locals).
2056 If only one is given, it is passed as both.
2056 If only one is given, it is passed as both.
2057 exit_ignore : bool (False)
2057 exit_ignore : bool (False)
2058 If True, then silence SystemExit for non-zero status (it is always
2058 If True, then silence SystemExit for non-zero status (it is always
2059 silenced for zero status, as it is so common).
2059 silenced for zero status, as it is so common).
2060 """
2060 """
2061 kw.setdefault('exit_ignore', False)
2061 kw.setdefault('exit_ignore', False)
2062
2062
2063 fname = os.path.abspath(os.path.expanduser(fname))
2063 fname = os.path.abspath(os.path.expanduser(fname))
2064
2064
2065 # Make sure we have a .py file
2065 # Make sure we have a .py file
2066 if not fname.endswith('.py'):
2066 if not fname.endswith('.py'):
2067 warn('File must end with .py to be run using execfile: <%s>' % fname)
2067 warn('File must end with .py to be run using execfile: <%s>' % fname)
2068
2068
2069 # Make sure we can open the file
2069 # Make sure we can open the file
2070 try:
2070 try:
2071 with open(fname) as thefile:
2071 with open(fname) as thefile:
2072 pass
2072 pass
2073 except:
2073 except:
2074 warn('Could not open file <%s> for safe execution.' % fname)
2074 warn('Could not open file <%s> for safe execution.' % fname)
2075 return
2075 return
2076
2076
2077 # Find things also in current directory. This is needed to mimic the
2077 # Find things also in current directory. This is needed to mimic the
2078 # behavior of running a script from the system command line, where
2078 # behavior of running a script from the system command line, where
2079 # Python inserts the script's directory into sys.path
2079 # Python inserts the script's directory into sys.path
2080 dname = os.path.dirname(fname)
2080 dname = os.path.dirname(fname)
2081
2081
2082 with prepended_to_syspath(dname):
2082 with prepended_to_syspath(dname):
2083 try:
2083 try:
2084 execfile(fname,*where)
2084 execfile(fname,*where)
2085 except SystemExit, status:
2085 except SystemExit, status:
2086 # If the call was made with 0 or None exit status (sys.exit(0)
2086 # If the call was made with 0 or None exit status (sys.exit(0)
2087 # or sys.exit() ), don't bother showing a traceback, as both of
2087 # or sys.exit() ), don't bother showing a traceback, as both of
2088 # these are considered normal by the OS:
2088 # these are considered normal by the OS:
2089 # > python -c'import sys;sys.exit(0)'; echo $?
2089 # > python -c'import sys;sys.exit(0)'; echo $?
2090 # 0
2090 # 0
2091 # > python -c'import sys;sys.exit()'; echo $?
2091 # > python -c'import sys;sys.exit()'; echo $?
2092 # 0
2092 # 0
2093 # For other exit status, we show the exception unless
2093 # For other exit status, we show the exception unless
2094 # explicitly silenced, but only in short form.
2094 # explicitly silenced, but only in short form.
2095 if status.code not in (0, None) and not kw['exit_ignore']:
2095 if status.code not in (0, None) and not kw['exit_ignore']:
2096 self.showtraceback(exception_only=True)
2096 self.showtraceback(exception_only=True)
2097 except:
2097 except:
2098 self.showtraceback()
2098 self.showtraceback()
2099
2099
2100 def safe_execfile_ipy(self, fname):
2100 def safe_execfile_ipy(self, fname):
2101 """Like safe_execfile, but for .ipy files with IPython syntax.
2101 """Like safe_execfile, but for .ipy files with IPython syntax.
2102
2102
2103 Parameters
2103 Parameters
2104 ----------
2104 ----------
2105 fname : str
2105 fname : str
2106 The name of the file to execute. The filename must have a
2106 The name of the file to execute. The filename must have a
2107 .ipy extension.
2107 .ipy extension.
2108 """
2108 """
2109 fname = os.path.abspath(os.path.expanduser(fname))
2109 fname = os.path.abspath(os.path.expanduser(fname))
2110
2110
2111 # Make sure we have a .py file
2111 # Make sure we have a .py file
2112 if not fname.endswith('.ipy'):
2112 if not fname.endswith('.ipy'):
2113 warn('File must end with .py to be run using execfile: <%s>' % fname)
2113 warn('File must end with .py to be run using execfile: <%s>' % fname)
2114
2114
2115 # Make sure we can open the file
2115 # Make sure we can open the file
2116 try:
2116 try:
2117 with open(fname) as thefile:
2117 with open(fname) as thefile:
2118 pass
2118 pass
2119 except:
2119 except:
2120 warn('Could not open file <%s> for safe execution.' % fname)
2120 warn('Could not open file <%s> for safe execution.' % fname)
2121 return
2121 return
2122
2122
2123 # Find things also in current directory. This is needed to mimic the
2123 # Find things also in current directory. This is needed to mimic the
2124 # behavior of running a script from the system command line, where
2124 # behavior of running a script from the system command line, where
2125 # Python inserts the script's directory into sys.path
2125 # Python inserts the script's directory into sys.path
2126 dname = os.path.dirname(fname)
2126 dname = os.path.dirname(fname)
2127
2127
2128 with prepended_to_syspath(dname):
2128 with prepended_to_syspath(dname):
2129 try:
2129 try:
2130 with open(fname) as thefile:
2130 with open(fname) as thefile:
2131 script = thefile.read()
2131 script = thefile.read()
2132 # self.runlines currently captures all exceptions
2132 # self.runlines currently captures all exceptions
2133 # raise in user code. It would be nice if there were
2133 # raise in user code. It would be nice if there were
2134 # versions of runlines, execfile that did raise, so
2134 # versions of runlines, execfile that did raise, so
2135 # we could catch the errors.
2135 # we could catch the errors.
2136 self.runlines(script, clean=True)
2136 self.runlines(script, clean=True)
2137 except:
2137 except:
2138 self.showtraceback()
2138 self.showtraceback()
2139 warn('Unknown failure executing file: <%s>' % fname)
2139 warn('Unknown failure executing file: <%s>' % fname)
2140
2140
2141 def run_cell(self, cell):
2141 def run_cell(self, cell):
2142 """Run the contents of an entire multiline 'cell' of code.
2142 """Run the contents of an entire multiline 'cell' of code.
2143
2143
2144 The cell is split into separate blocks which can be executed
2144 The cell is split into separate blocks which can be executed
2145 individually. Then, based on how many blocks there are, they are
2145 individually. Then, based on how many blocks there are, they are
2146 executed as follows:
2146 executed as follows:
2147
2147
2148 - A single block: 'single' mode.
2148 - A single block: 'single' mode.
2149
2149
2150 If there's more than one block, it depends:
2150 If there's more than one block, it depends:
2151
2151
2152 - if the last one is no more than two lines long, run all but the last
2152 - if the last one is no more than two lines long, run all but the last
2153 in 'exec' mode and the very last one in 'single' mode. This makes it
2153 in 'exec' mode and the very last one in 'single' mode. This makes it
2154 easy to type simple expressions at the end to see computed values. -
2154 easy to type simple expressions at the end to see computed values. -
2155 otherwise (last one is also multiline), run all in 'exec' mode
2155 otherwise (last one is also multiline), run all in 'exec' mode
2156
2156
2157 When code is executed in 'single' mode, :func:`sys.displayhook` fires,
2157 When code is executed in 'single' mode, :func:`sys.displayhook` fires,
2158 results are displayed and output prompts are computed. In 'exec' mode,
2158 results are displayed and output prompts are computed. In 'exec' mode,
2159 no results are displayed unless :func:`print` is called explicitly;
2159 no results are displayed unless :func:`print` is called explicitly;
2160 this mode is more akin to running a script.
2160 this mode is more akin to running a script.
2161
2161
2162 Parameters
2162 Parameters
2163 ----------
2163 ----------
2164 cell : str
2164 cell : str
2165 A single or multiline string.
2165 A single or multiline string.
2166 """
2166 """
2167 #################################################################
2167 #################################################################
2168 # FIXME
2168 # FIXME
2169 # =====
2169 # =====
2170 # This execution logic should stop calling runlines altogether, and
2170 # This execution logic should stop calling runlines altogether, and
2171 # instead we should do what runlines does, in a controlled manner, here
2171 # instead we should do what runlines does, in a controlled manner, here
2172 # (runlines mutates lots of state as it goes calling sub-methods that
2172 # (runlines mutates lots of state as it goes calling sub-methods that
2173 # also mutate state). Basically we should:
2173 # also mutate state). Basically we should:
2174 # - apply dynamic transforms for single-line input (the ones that
2174 # - apply dynamic transforms for single-line input (the ones that
2175 # split_blocks won't apply since they need context).
2175 # split_blocks won't apply since they need context).
2176 # - increment the global execution counter (we need to pull that out
2176 # - increment the global execution counter (we need to pull that out
2177 # from outputcache's control; outputcache should instead read it from
2177 # from outputcache's control; outputcache should instead read it from
2178 # the main object).
2178 # the main object).
2179 # - do any logging of input
2179 # - do any logging of input
2180 # - update histories (raw/translated)
2180 # - update histories (raw/translated)
2181 # - then, call plain runsource (for single blocks, so displayhook is
2181 # - then, call plain runsource (for single blocks, so displayhook is
2182 # triggered) or runcode (for multiline blocks in exec mode).
2182 # triggered) or runcode (for multiline blocks in exec mode).
2183 #
2183 #
2184 # Once this is done, we'll be able to stop using runlines and we'll
2184 # Once this is done, we'll be able to stop using runlines and we'll
2185 # also have a much cleaner separation of logging, input history and
2185 # also have a much cleaner separation of logging, input history and
2186 # output cache management.
2186 # output cache management.
2187 #################################################################
2187 #################################################################
2188
2188
2189 # We need to break up the input into executable blocks that can be run
2189 # We need to break up the input into executable blocks that can be run
2190 # in 'single' mode, to provide comfortable user behavior.
2190 # in 'single' mode, to provide comfortable user behavior.
2191 blocks = self.input_splitter.split_blocks(cell)
2191 blocks = self.input_splitter.split_blocks(cell)
2192
2192
2193 if not blocks:
2193 if not blocks:
2194 return
2194 return
2195
2195
2196 # Single-block input should behave like an interactive prompt
2196 # Single-block input should behave like an interactive prompt
2197 if len(blocks) == 1:
2197 if len(blocks) == 1:
2198 self.runlines(blocks[0])
2198 self.runlines(blocks[0])
2199 return
2199 return
2200
2200
2201 # In multi-block input, if the last block is a simple (one-two lines)
2201 # In multi-block input, if the last block is a simple (one-two lines)
2202 # expression, run it in single mode so it produces output. Otherwise
2202 # expression, run it in single mode so it produces output. Otherwise
2203 # just feed the whole thing to runcode.
2203 # just feed the whole thing to runcode.
2204 # This seems like a reasonable usability design.
2204 # This seems like a reasonable usability design.
2205 last = blocks[-1]
2205 last = blocks[-1]
2206
2206
2207 # Note: below, whenever we call runcode, we must sync history
2207 # Note: below, whenever we call runcode, we must sync history
2208 # ourselves, because runcode is NOT meant to manage history at all.
2208 # ourselves, because runcode is NOT meant to manage history at all.
2209 if len(last.splitlines()) < 2:
2209 if len(last.splitlines()) < 2:
2210 # Get the main body to run as a cell
2210 # Get the main body to run as a cell
2211 body = ''.join(blocks[:-1])
2211 body = ''.join(blocks[:-1])
2212 self.input_hist.append(body)
2212 self.input_hist.append(body)
2213 self.input_hist_raw.append(body)
2213 self.input_hist_raw.append(body)
2214 retcode = self.runcode(body, post_execute=False)
2214 retcode = self.runcode(body, post_execute=False)
2215 if retcode==0:
2215 if retcode==0:
2216 # And the last expression via runlines so it produces output
2216 # And the last expression via runlines so it produces output
2217 self.runlines(last)
2217 self.runlines(last)
2218 else:
2218 else:
2219 # Run the whole cell as one entity
2219 # Run the whole cell as one entity
2220 self.input_hist.append(cell)
2220 self.input_hist.append(cell)
2221 self.input_hist_raw.append(cell)
2221 self.input_hist_raw.append(cell)
2222 self.runcode(cell)
2222 self.runcode(cell)
2223
2223
2224 def runlines(self, lines, clean=False):
2224 def runlines(self, lines, clean=False):
2225 """Run a string of one or more lines of source.
2225 """Run a string of one or more lines of source.
2226
2226
2227 This method is capable of running a string containing multiple source
2227 This method is capable of running a string containing multiple source
2228 lines, as if they had been entered at the IPython prompt. Since it
2228 lines, as if they had been entered at the IPython prompt. Since it
2229 exposes IPython's processing machinery, the given strings can contain
2229 exposes IPython's processing machinery, the given strings can contain
2230 magic calls (%magic), special shell access (!cmd), etc.
2230 magic calls (%magic), special shell access (!cmd), etc.
2231 """
2231 """
2232
2232
2233 if isinstance(lines, (list, tuple)):
2233 if isinstance(lines, (list, tuple)):
2234 lines = '\n'.join(lines)
2234 lines = '\n'.join(lines)
2235
2235
2236 if clean:
2236 if clean:
2237 lines = self._cleanup_ipy_script(lines)
2237 lines = self._cleanup_ipy_script(lines)
2238
2238
2239 # We must start with a clean buffer, in case this is run from an
2239 # We must start with a clean buffer, in case this is run from an
2240 # interactive IPython session (via a magic, for example).
2240 # interactive IPython session (via a magic, for example).
2241 self.resetbuffer()
2241 self.resetbuffer()
2242 lines = lines.splitlines()
2242 lines = lines.splitlines()
2243 more = 0
2243 more = 0
2244 with nested(self.builtin_trap, self.display_trap):
2244 with nested(self.builtin_trap, self.display_trap):
2245 for line in lines:
2245 for line in lines:
2246 # skip blank lines so we don't mess up the prompt counter, but
2246 # skip blank lines so we don't mess up the prompt counter, but
2247 # do NOT skip even a blank line if we are in a code block (more
2247 # do NOT skip even a blank line if we are in a code block (more
2248 # is true)
2248 # is true)
2249
2249
2250 if line or more:
2250 if line or more:
2251 # push to raw history, so hist line numbers stay in sync
2251 # push to raw history, so hist line numbers stay in sync
2252 self.input_hist_raw.append(line + '\n')
2252 self.input_hist_raw.append(line + '\n')
2253 prefiltered = self.prefilter_manager.prefilter_lines(line,
2253 prefiltered = self.prefilter_manager.prefilter_lines(line,
2254 more)
2254 more)
2255 more = self.push_line(prefiltered)
2255 more = self.push_line(prefiltered)
2256 # IPython's runsource returns None if there was an error
2256 # IPython's runsource returns None if there was an error
2257 # compiling the code. This allows us to stop processing
2257 # compiling the code. This allows us to stop processing
2258 # right away, so the user gets the error message at the
2258 # right away, so the user gets the error message at the
2259 # right place.
2259 # right place.
2260 if more is None:
2260 if more is None:
2261 break
2261 break
2262 else:
2262 else:
2263 self.input_hist_raw.append("\n")
2263 self.input_hist_raw.append("\n")
2264 # final newline in case the input didn't have it, so that the code
2264 # final newline in case the input didn't have it, so that the code
2265 # actually does get executed
2265 # actually does get executed
2266 if more:
2266 if more:
2267 self.push_line('\n')
2267 self.push_line('\n')
2268
2268
2269 def runsource(self, source, filename='<input>', symbol='single'):
2269 def runsource(self, source, filename='<input>', symbol='single'):
2270 """Compile and run some source in the interpreter.
2270 """Compile and run some source in the interpreter.
2271
2271
2272 Arguments are as for compile_command().
2272 Arguments are as for compile_command().
2273
2273
2274 One several things can happen:
2274 One several things can happen:
2275
2275
2276 1) The input is incorrect; compile_command() raised an
2276 1) The input is incorrect; compile_command() raised an
2277 exception (SyntaxError or OverflowError). A syntax traceback
2277 exception (SyntaxError or OverflowError). A syntax traceback
2278 will be printed by calling the showsyntaxerror() method.
2278 will be printed by calling the showsyntaxerror() method.
2279
2279
2280 2) The input is incomplete, and more input is required;
2280 2) The input is incomplete, and more input is required;
2281 compile_command() returned None. Nothing happens.
2281 compile_command() returned None. Nothing happens.
2282
2282
2283 3) The input is complete; compile_command() returned a code
2283 3) The input is complete; compile_command() returned a code
2284 object. The code is executed by calling self.runcode() (which
2284 object. The code is executed by calling self.runcode() (which
2285 also handles run-time exceptions, except for SystemExit).
2285 also handles run-time exceptions, except for SystemExit).
2286
2286
2287 The return value is:
2287 The return value is:
2288
2288
2289 - True in case 2
2289 - True in case 2
2290
2290
2291 - False in the other cases, unless an exception is raised, where
2291 - False in the other cases, unless an exception is raised, where
2292 None is returned instead. This can be used by external callers to
2292 None is returned instead. This can be used by external callers to
2293 know whether to continue feeding input or not.
2293 know whether to continue feeding input or not.
2294
2294
2295 The return value can be used to decide whether to use sys.ps1 or
2295 The return value can be used to decide whether to use sys.ps1 or
2296 sys.ps2 to prompt the next line."""
2296 sys.ps2 to prompt the next line."""
2297
2297
2298 # We need to ensure that the source is unicode from here on.
2298 # We need to ensure that the source is unicode from here on.
2299 if type(source)==str:
2299 if type(source)==str:
2300 source = source.decode(self.stdin_encoding)
2300 source = source.decode(self.stdin_encoding)
2301
2301
2302 # if the source code has leading blanks, add 'if 1:\n' to it
2302 # if the source code has leading blanks, add 'if 1:\n' to it
2303 # this allows execution of indented pasted code. It is tempting
2303 # this allows execution of indented pasted code. It is tempting
2304 # to add '\n' at the end of source to run commands like ' a=1'
2304 # to add '\n' at the end of source to run commands like ' a=1'
2305 # directly, but this fails for more complicated scenarios
2305 # directly, but this fails for more complicated scenarios
2306
2306
2307 if source[:1] in [' ', '\t']:
2307 if source[:1] in [' ', '\t']:
2308 source = u'if 1:\n%s' % source
2308 source = u'if 1:\n%s' % source
2309
2309
2310 try:
2310 try:
2311 code = self.compile(source,filename,symbol)
2311 code = self.compile(source,filename,symbol)
2312 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2312 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2313 # Case 1
2313 # Case 1
2314 self.showsyntaxerror(filename)
2314 self.showsyntaxerror(filename)
2315 return None
2315 return None
2316
2316
2317 if code is None:
2317 if code is None:
2318 # Case 2
2318 # Case 2
2319 return True
2319 return True
2320
2320
2321 # Case 3
2321 # Case 3
2322 # We store the code object so that threaded shells and
2322 # We store the code object so that threaded shells and
2323 # custom exception handlers can access all this info if needed.
2323 # custom exception handlers can access all this info if needed.
2324 # The source corresponding to this can be obtained from the
2324 # The source corresponding to this can be obtained from the
2325 # buffer attribute as '\n'.join(self.buffer).
2325 # buffer attribute as '\n'.join(self.buffer).
2326 self.code_to_run = code
2326 self.code_to_run = code
2327 # now actually execute the code object
2327 # now actually execute the code object
2328 if self.runcode(code) == 0:
2328 if self.runcode(code) == 0:
2329 return False
2329 return False
2330 else:
2330 else:
2331 return None
2331 return None
2332
2332
2333 def runcode(self, code_obj, post_execute=True):
2333 def runcode(self, code_obj, post_execute=True):
2334 """Execute a code object.
2334 """Execute a code object.
2335
2335
2336 When an exception occurs, self.showtraceback() is called to display a
2336 When an exception occurs, self.showtraceback() is called to display a
2337 traceback.
2337 traceback.
2338
2338
2339 Return value: a flag indicating whether the code to be run completed
2339 Return value: a flag indicating whether the code to be run completed
2340 successfully:
2340 successfully:
2341
2341
2342 - 0: successful execution.
2342 - 0: successful execution.
2343 - 1: an error occurred.
2343 - 1: an error occurred.
2344 """
2344 """
2345
2345
2346 # Set our own excepthook in case the user code tries to call it
2346 # Set our own excepthook in case the user code tries to call it
2347 # directly, so that the IPython crash handler doesn't get triggered
2347 # directly, so that the IPython crash handler doesn't get triggered
2348 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2348 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2349
2349
2350 # we save the original sys.excepthook in the instance, in case config
2350 # we save the original sys.excepthook in the instance, in case config
2351 # code (such as magics) needs access to it.
2351 # code (such as magics) needs access to it.
2352 self.sys_excepthook = old_excepthook
2352 self.sys_excepthook = old_excepthook
2353 outflag = 1 # happens in more places, so it's easier as default
2353 outflag = 1 # happens in more places, so it's easier as default
2354 try:
2354 try:
2355 try:
2355 try:
2356 self.hooks.pre_runcode_hook()
2356 self.hooks.pre_runcode_hook()
2357 #rprint('Running code') # dbg
2357 #rprint('Running code') # dbg
2358 exec code_obj in self.user_global_ns, self.user_ns
2358 exec code_obj in self.user_global_ns, self.user_ns
2359 finally:
2359 finally:
2360 # Reset our crash handler in place
2360 # Reset our crash handler in place
2361 sys.excepthook = old_excepthook
2361 sys.excepthook = old_excepthook
2362 except SystemExit:
2362 except SystemExit:
2363 self.resetbuffer()
2363 self.resetbuffer()
2364 self.showtraceback(exception_only=True)
2364 self.showtraceback(exception_only=True)
2365 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2365 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2366 except self.custom_exceptions:
2366 except self.custom_exceptions:
2367 etype,value,tb = sys.exc_info()
2367 etype,value,tb = sys.exc_info()
2368 self.CustomTB(etype,value,tb)
2368 self.CustomTB(etype,value,tb)
2369 except:
2369 except:
2370 self.showtraceback()
2370 self.showtraceback()
2371 else:
2371 else:
2372 outflag = 0
2372 outflag = 0
2373 if softspace(sys.stdout, 0):
2373 if softspace(sys.stdout, 0):
2374 print
2374 print
2375
2375
2376 # Execute any registered post-execution functions. Here, any errors
2376 # Execute any registered post-execution functions. Here, any errors
2377 # are reported only minimally and just on the terminal, because the
2377 # are reported only minimally and just on the terminal, because the
2378 # main exception channel may be occupied with a user traceback.
2378 # main exception channel may be occupied with a user traceback.
2379 # FIXME: we need to think this mechanism a little more carefully.
2379 # FIXME: we need to think this mechanism a little more carefully.
2380 if post_execute:
2380 if post_execute:
2381 for func in self._post_execute:
2381 for func in self._post_execute:
2382 try:
2382 try:
2383 func()
2383 func()
2384 except:
2384 except:
2385 head = '[ ERROR ] Evaluating post_execute function: %s' % \
2385 head = '[ ERROR ] Evaluating post_execute function: %s' % \
2386 func
2386 func
2387 print >> io.Term.cout, head
2387 print >> io.Term.cout, head
2388 print >> io.Term.cout, self._simple_error()
2388 print >> io.Term.cout, self._simple_error()
2389 print >> io.Term.cout, 'Removing from post_execute'
2389 print >> io.Term.cout, 'Removing from post_execute'
2390 self._post_execute.remove(func)
2390 self._post_execute.remove(func)
2391
2391
2392 # Flush out code object which has been run (and source)
2392 # Flush out code object which has been run (and source)
2393 self.code_to_run = None
2393 self.code_to_run = None
2394 return outflag
2394 return outflag
2395
2395
2396 def push_line(self, line):
2396 def push_line(self, line):
2397 """Push a line to the interpreter.
2397 """Push a line to the interpreter.
2398
2398
2399 The line should not have a trailing newline; it may have
2399 The line should not have a trailing newline; it may have
2400 internal newlines. The line is appended to a buffer and the
2400 internal newlines. The line is appended to a buffer and the
2401 interpreter's runsource() method is called with the
2401 interpreter's runsource() method is called with the
2402 concatenated contents of the buffer as source. If this
2402 concatenated contents of the buffer as source. If this
2403 indicates that the command was executed or invalid, the buffer
2403 indicates that the command was executed or invalid, the buffer
2404 is reset; otherwise, the command is incomplete, and the buffer
2404 is reset; otherwise, the command is incomplete, and the buffer
2405 is left as it was after the line was appended. The return
2405 is left as it was after the line was appended. The return
2406 value is 1 if more input is required, 0 if the line was dealt
2406 value is 1 if more input is required, 0 if the line was dealt
2407 with in some way (this is the same as runsource()).
2407 with in some way (this is the same as runsource()).
2408 """
2408 """
2409
2409
2410 # autoindent management should be done here, and not in the
2410 # autoindent management should be done here, and not in the
2411 # interactive loop, since that one is only seen by keyboard input. We
2411 # interactive loop, since that one is only seen by keyboard input. We
2412 # need this done correctly even for code run via runlines (which uses
2412 # need this done correctly even for code run via runlines (which uses
2413 # push).
2413 # push).
2414
2414
2415 #print 'push line: <%s>' % line # dbg
2415 #print 'push line: <%s>' % line # dbg
2416 for subline in line.splitlines():
2416 for subline in line.splitlines():
2417 self._autoindent_update(subline)
2417 self._autoindent_update(subline)
2418 self.buffer.append(line)
2418 self.buffer.append(line)
2419 more = self.runsource('\n'.join(self.buffer), self.filename)
2419 more = self.runsource('\n'.join(self.buffer), self.filename)
2420 if not more:
2420 if not more:
2421 self.resetbuffer()
2421 self.resetbuffer()
2422 return more
2422 return more
2423
2423
2424 def resetbuffer(self):
2424 def resetbuffer(self):
2425 """Reset the input buffer."""
2425 """Reset the input buffer."""
2426 self.buffer[:] = []
2426 self.buffer[:] = []
2427
2427
2428 def _is_secondary_block_start(self, s):
2428 def _is_secondary_block_start(self, s):
2429 if not s.endswith(':'):
2429 if not s.endswith(':'):
2430 return False
2430 return False
2431 if (s.startswith('elif') or
2431 if (s.startswith('elif') or
2432 s.startswith('else') or
2432 s.startswith('else') or
2433 s.startswith('except') or
2433 s.startswith('except') or
2434 s.startswith('finally')):
2434 s.startswith('finally')):
2435 return True
2435 return True
2436
2436
2437 def _cleanup_ipy_script(self, script):
2437 def _cleanup_ipy_script(self, script):
2438 """Make a script safe for self.runlines()
2438 """Make a script safe for self.runlines()
2439
2439
2440 Currently, IPython is lines based, with blocks being detected by
2440 Currently, IPython is lines based, with blocks being detected by
2441 empty lines. This is a problem for block based scripts that may
2441 empty lines. This is a problem for block based scripts that may
2442 not have empty lines after blocks. This script adds those empty
2442 not have empty lines after blocks. This script adds those empty
2443 lines to make scripts safe for running in the current line based
2443 lines to make scripts safe for running in the current line based
2444 IPython.
2444 IPython.
2445 """
2445 """
2446 res = []
2446 res = []
2447 lines = script.splitlines()
2447 lines = script.splitlines()
2448 level = 0
2448 level = 0
2449
2449
2450 for l in lines:
2450 for l in lines:
2451 lstripped = l.lstrip()
2451 lstripped = l.lstrip()
2452 stripped = l.strip()
2452 stripped = l.strip()
2453 if not stripped:
2453 if not stripped:
2454 continue
2454 continue
2455 newlevel = len(l) - len(lstripped)
2455 newlevel = len(l) - len(lstripped)
2456 if level > 0 and newlevel == 0 and \
2456 if level > 0 and newlevel == 0 and \
2457 not self._is_secondary_block_start(stripped):
2457 not self._is_secondary_block_start(stripped):
2458 # add empty line
2458 # add empty line
2459 res.append('')
2459 res.append('')
2460 res.append(l)
2460 res.append(l)
2461 level = newlevel
2461 level = newlevel
2462
2462
2463 return '\n'.join(res) + '\n'
2463 return '\n'.join(res) + '\n'
2464
2464
2465 def _autoindent_update(self,line):
2465 def _autoindent_update(self,line):
2466 """Keep track of the indent level."""
2466 """Keep track of the indent level."""
2467
2467
2468 #debugx('line')
2468 #debugx('line')
2469 #debugx('self.indent_current_nsp')
2469 #debugx('self.indent_current_nsp')
2470 if self.autoindent:
2470 if self.autoindent:
2471 if line:
2471 if line:
2472 inisp = num_ini_spaces(line)
2472 inisp = num_ini_spaces(line)
2473 if inisp < self.indent_current_nsp:
2473 if inisp < self.indent_current_nsp:
2474 self.indent_current_nsp = inisp
2474 self.indent_current_nsp = inisp
2475
2475
2476 if line[-1] == ':':
2476 if line[-1] == ':':
2477 self.indent_current_nsp += 4
2477 self.indent_current_nsp += 4
2478 elif dedent_re.match(line):
2478 elif dedent_re.match(line):
2479 self.indent_current_nsp -= 4
2479 self.indent_current_nsp -= 4
2480 else:
2480 else:
2481 self.indent_current_nsp = 0
2481 self.indent_current_nsp = 0
2482
2482
2483 #-------------------------------------------------------------------------
2483 #-------------------------------------------------------------------------
2484 # Things related to GUI support and pylab
2484 # Things related to GUI support and pylab
2485 #-------------------------------------------------------------------------
2485 #-------------------------------------------------------------------------
2486
2486
2487 def enable_pylab(self, gui=None):
2487 def enable_pylab(self, gui=None):
2488 raise NotImplementedError('Implement enable_pylab in a subclass')
2488 raise NotImplementedError('Implement enable_pylab in a subclass')
2489
2489
2490 #-------------------------------------------------------------------------
2490 #-------------------------------------------------------------------------
2491 # Utilities
2491 # Utilities
2492 #-------------------------------------------------------------------------
2492 #-------------------------------------------------------------------------
2493
2493
2494 def var_expand(self,cmd,depth=0):
2494 def var_expand(self,cmd,depth=0):
2495 """Expand python variables in a string.
2495 """Expand python variables in a string.
2496
2496
2497 The depth argument indicates how many frames above the caller should
2497 The depth argument indicates how many frames above the caller should
2498 be walked to look for the local namespace where to expand variables.
2498 be walked to look for the local namespace where to expand variables.
2499
2499
2500 The global namespace for expansion is always the user's interactive
2500 The global namespace for expansion is always the user's interactive
2501 namespace.
2501 namespace.
2502 """
2502 """
2503
2503
2504 return str(ItplNS(cmd,
2504 return str(ItplNS(cmd,
2505 self.user_ns, # globals
2505 self.user_ns, # globals
2506 # Skip our own frame in searching for locals:
2506 # Skip our own frame in searching for locals:
2507 sys._getframe(depth+1).f_locals # locals
2507 sys._getframe(depth+1).f_locals # locals
2508 ))
2508 ))
2509
2509
2510 def mktempfile(self,data=None):
2510 def mktempfile(self,data=None):
2511 """Make a new tempfile and return its filename.
2511 """Make a new tempfile and return its filename.
2512
2512
2513 This makes a call to tempfile.mktemp, but it registers the created
2513 This makes a call to tempfile.mktemp, but it registers the created
2514 filename internally so ipython cleans it up at exit time.
2514 filename internally so ipython cleans it up at exit time.
2515
2515
2516 Optional inputs:
2516 Optional inputs:
2517
2517
2518 - data(None): if data is given, it gets written out to the temp file
2518 - data(None): if data is given, it gets written out to the temp file
2519 immediately, and the file is closed again."""
2519 immediately, and the file is closed again."""
2520
2520
2521 filename = tempfile.mktemp('.py','ipython_edit_')
2521 filename = tempfile.mktemp('.py','ipython_edit_')
2522 self.tempfiles.append(filename)
2522 self.tempfiles.append(filename)
2523
2523
2524 if data:
2524 if data:
2525 tmp_file = open(filename,'w')
2525 tmp_file = open(filename,'w')
2526 tmp_file.write(data)
2526 tmp_file.write(data)
2527 tmp_file.close()
2527 tmp_file.close()
2528 return filename
2528 return filename
2529
2529
2530 # TODO: This should be removed when Term is refactored.
2530 # TODO: This should be removed when Term is refactored.
2531 def write(self,data):
2531 def write(self,data):
2532 """Write a string to the default output"""
2532 """Write a string to the default output"""
2533 io.Term.cout.write(data)
2533 io.Term.cout.write(data)
2534
2534
2535 # TODO: This should be removed when Term is refactored.
2535 # TODO: This should be removed when Term is refactored.
2536 def write_err(self,data):
2536 def write_err(self,data):
2537 """Write a string to the default error output"""
2537 """Write a string to the default error output"""
2538 io.Term.cerr.write(data)
2538 io.Term.cerr.write(data)
2539
2539
2540 def ask_yes_no(self,prompt,default=True):
2540 def ask_yes_no(self,prompt,default=True):
2541 if self.quiet:
2541 if self.quiet:
2542 return True
2542 return True
2543 return ask_yes_no(prompt,default)
2543 return ask_yes_no(prompt,default)
2544
2544
2545 def show_usage(self):
2545 def show_usage(self):
2546 """Show a usage message"""
2546 """Show a usage message"""
2547 page.page(IPython.core.usage.interactive_usage)
2547 page.page(IPython.core.usage.interactive_usage)
2548
2548
2549 #-------------------------------------------------------------------------
2549 #-------------------------------------------------------------------------
2550 # Things related to IPython exiting
2550 # Things related to IPython exiting
2551 #-------------------------------------------------------------------------
2551 #-------------------------------------------------------------------------
2552 def atexit_operations(self):
2552 def atexit_operations(self):
2553 """This will be executed at the time of exit.
2553 """This will be executed at the time of exit.
2554
2554
2555 Cleanup operations and saving of persistent data that is done
2555 Cleanup operations and saving of persistent data that is done
2556 unconditionally by IPython should be performed here.
2556 unconditionally by IPython should be performed here.
2557
2557
2558 For things that may depend on startup flags or platform specifics (such
2558 For things that may depend on startup flags or platform specifics (such
2559 as having readline or not), register a separate atexit function in the
2559 as having readline or not), register a separate atexit function in the
2560 code that has the appropriate information, rather than trying to
2560 code that has the appropriate information, rather than trying to
2561 clutter
2561 clutter
2562 """
2562 """
2563 # Cleanup all tempfiles left around
2563 # Cleanup all tempfiles left around
2564 for tfile in self.tempfiles:
2564 for tfile in self.tempfiles:
2565 try:
2565 try:
2566 os.unlink(tfile)
2566 os.unlink(tfile)
2567 except OSError:
2567 except OSError:
2568 pass
2568 pass
2569
2569
2570 # Clear all user namespaces to release all references cleanly.
2570 # Clear all user namespaces to release all references cleanly.
2571 self.reset()
2571 self.reset()
2572
2572
2573 # Run user hooks
2573 # Run user hooks
2574 self.hooks.shutdown_hook()
2574 self.hooks.shutdown_hook()
2575
2575
2576 def cleanup(self):
2576 def cleanup(self):
2577 self.restore_sys_module_state()
2577 self.restore_sys_module_state()
2578
2578
2579
2579
2580 class InteractiveShellABC(object):
2580 class InteractiveShellABC(object):
2581 """An abstract base class for InteractiveShell."""
2581 """An abstract base class for InteractiveShell."""
2582 __metaclass__ = abc.ABCMeta
2582 __metaclass__ = abc.ABCMeta
2583
2583
2584 InteractiveShellABC.register(InteractiveShell)
2584 InteractiveShellABC.register(InteractiveShell)
@@ -1,658 +1,658 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the inputsplitter module.
2 """Tests for the inputsplitter module.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2010 The IPython Development Team
5 # Copyright (C) 2010 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # stdlib
14 # stdlib
15 import unittest
15 import unittest
16 import sys
16 import sys
17
17
18 # Third party
18 # Third party
19 import nose.tools as nt
19 import nose.tools as nt
20
20
21 # Our own
21 # Our own
22 from IPython.core import inputsplitter as isp
22 from IPython.core import inputsplitter as isp
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Semi-complete examples (also used as tests)
25 # Semi-complete examples (also used as tests)
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 # Note: at the bottom, there's a slightly more complete version of this that
28 # Note: at the bottom, there's a slightly more complete version of this that
29 # can be useful during development of code here.
29 # can be useful during development of code here.
30
30
31 def mini_interactive_loop(raw_input):
31 def mini_interactive_loop(raw_input):
32 """Minimal example of the logic of an interactive interpreter loop.
32 """Minimal example of the logic of an interactive interpreter loop.
33
33
34 This serves as an example, and it is used by the test system with a fake
34 This serves as an example, and it is used by the test system with a fake
35 raw_input that simulates interactive input."""
35 raw_input that simulates interactive input."""
36
36
37 from IPython.core.inputsplitter import InputSplitter
37 from IPython.core.inputsplitter import InputSplitter
38
38
39 isp = InputSplitter()
39 isp = InputSplitter()
40 # In practice, this input loop would be wrapped in an outside loop to read
40 # In practice, this input loop would be wrapped in an outside loop to read
41 # input indefinitely, until some exit/quit command was issued. Here we
41 # input indefinitely, until some exit/quit command was issued. Here we
42 # only illustrate the basic inner loop.
42 # only illustrate the basic inner loop.
43 while isp.push_accepts_more():
43 while isp.push_accepts_more():
44 indent = ' '*isp.indent_spaces
44 indent = ' '*isp.indent_spaces
45 prompt = '>>> ' + indent
45 prompt = '>>> ' + indent
46 line = indent + raw_input(prompt)
46 line = indent + raw_input(prompt)
47 isp.push(line)
47 isp.push(line)
48
48
49 # Here we just return input so we can use it in a test suite, but a real
49 # Here we just return input so we can use it in a test suite, but a real
50 # interpreter would instead send it for execution somewhere.
50 # interpreter would instead send it for execution somewhere.
51 src = isp.source_reset()
51 src = isp.source_reset()
52 #print 'Input source was:\n', src # dbg
52 #print 'Input source was:\n', src # dbg
53 return src
53 return src
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Test utilities, just for local use
56 # Test utilities, just for local use
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 def assemble(block):
59 def assemble(block):
60 """Assemble a block into multi-line sub-blocks."""
60 """Assemble a block into multi-line sub-blocks."""
61 return ['\n'.join(sub_block)+'\n' for sub_block in block]
61 return ['\n'.join(sub_block)+'\n' for sub_block in block]
62
62
63
63
64 def pseudo_input(lines):
64 def pseudo_input(lines):
65 """Return a function that acts like raw_input but feeds the input list."""
65 """Return a function that acts like raw_input but feeds the input list."""
66 ilines = iter(lines)
66 ilines = iter(lines)
67 def raw_in(prompt):
67 def raw_in(prompt):
68 try:
68 try:
69 return next(ilines)
69 return next(ilines)
70 except StopIteration:
70 except StopIteration:
71 return ''
71 return ''
72 return raw_in
72 return raw_in
73
73
74 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
75 # Tests
75 # Tests
76 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
77 def test_spaces():
77 def test_spaces():
78 tests = [('', 0),
78 tests = [('', 0),
79 (' ', 1),
79 (' ', 1),
80 ('\n', 0),
80 ('\n', 0),
81 (' \n', 1),
81 (' \n', 1),
82 ('x', 0),
82 ('x', 0),
83 (' x', 1),
83 (' x', 1),
84 (' x',2),
84 (' x',2),
85 (' x',4),
85 (' x',4),
86 # Note: tabs are counted as a single whitespace!
86 # Note: tabs are counted as a single whitespace!
87 ('\tx', 1),
87 ('\tx', 1),
88 ('\t x', 2),
88 ('\t x', 2),
89 ]
89 ]
90
90
91 for s, nsp in tests:
91 for s, nsp in tests:
92 nt.assert_equal(isp.num_ini_spaces(s), nsp)
92 nt.assert_equal(isp.num_ini_spaces(s), nsp)
93
93
94
94
95 def test_remove_comments():
95 def test_remove_comments():
96 tests = [('text', 'text'),
96 tests = [('text', 'text'),
97 ('text # comment', 'text '),
97 ('text # comment', 'text '),
98 ('text # comment\n', 'text \n'),
98 ('text # comment\n', 'text \n'),
99 ('text # comment \n', 'text \n'),
99 ('text # comment \n', 'text \n'),
100 ('line # c \nline\n','line \nline\n'),
100 ('line # c \nline\n','line \nline\n'),
101 ('line # c \nline#c2 \nline\nline #c\n\n',
101 ('line # c \nline#c2 \nline\nline #c\n\n',
102 'line \nline\nline\nline \n\n'),
102 'line \nline\nline\nline \n\n'),
103 ]
103 ]
104
104
105 for inp, out in tests:
105 for inp, out in tests:
106 nt.assert_equal(isp.remove_comments(inp), out)
106 nt.assert_equal(isp.remove_comments(inp), out)
107
107
108
108
109 def test_get_input_encoding():
109 def test_get_input_encoding():
110 encoding = isp.get_input_encoding()
110 encoding = isp.get_input_encoding()
111 nt.assert_true(isinstance(encoding, basestring))
111 nt.assert_true(isinstance(encoding, basestring))
112 # simple-minded check that at least encoding a simple string works with the
112 # simple-minded check that at least encoding a simple string works with the
113 # encoding we got.
113 # encoding we got.
114 nt.assert_equal('test'.encode(encoding), 'test')
114 nt.assert_equal('test'.encode(encoding), 'test')
115
115
116
116
117 class NoInputEncodingTestCase(unittest.TestCase):
117 class NoInputEncodingTestCase(unittest.TestCase):
118 def setUp(self):
118 def setUp(self):
119 self.old_stdin = sys.stdin
119 self.old_stdin = sys.stdin
120 class X: pass
120 class X: pass
121 fake_stdin = X()
121 fake_stdin = X()
122 sys.stdin = fake_stdin
122 sys.stdin = fake_stdin
123
123
124 def test(self):
124 def test(self):
125 # Verify that if sys.stdin has no 'encoding' attribute we do the right
125 # Verify that if sys.stdin has no 'encoding' attribute we do the right
126 # thing
126 # thing
127 enc = isp.get_input_encoding()
127 enc = isp.get_input_encoding()
128 self.assertEqual(enc, 'ascii')
128 self.assertEqual(enc, 'ascii')
129
129
130 def tearDown(self):
130 def tearDown(self):
131 sys.stdin = self.old_stdin
131 sys.stdin = self.old_stdin
132
132
133
133
134 class InputSplitterTestCase(unittest.TestCase):
134 class InputSplitterTestCase(unittest.TestCase):
135 def setUp(self):
135 def setUp(self):
136 self.isp = isp.InputSplitter()
136 self.isp = isp.InputSplitter()
137
137
138 def test_reset(self):
138 def test_reset(self):
139 isp = self.isp
139 isp = self.isp
140 isp.push('x=1')
140 isp.push('x=1')
141 isp.reset()
141 isp.reset()
142 self.assertEqual(isp._buffer, [])
142 self.assertEqual(isp._buffer, [])
143 self.assertEqual(isp.indent_spaces, 0)
143 self.assertEqual(isp.indent_spaces, 0)
144 self.assertEqual(isp.source, '')
144 self.assertEqual(isp.source, '')
145 self.assertEqual(isp.code, None)
145 self.assertEqual(isp.code, None)
146 self.assertEqual(isp._is_complete, False)
146 self.assertEqual(isp._is_complete, False)
147
147
148 def test_source(self):
148 def test_source(self):
149 self.isp._store('1')
149 self.isp._store('1')
150 self.isp._store('2')
150 self.isp._store('2')
151 self.assertEqual(self.isp.source, '1\n2\n')
151 self.assertEqual(self.isp.source, '1\n2\n')
152 self.assertTrue(len(self.isp._buffer)>0)
152 self.assertTrue(len(self.isp._buffer)>0)
153 self.assertEqual(self.isp.source_reset(), '1\n2\n')
153 self.assertEqual(self.isp.source_reset(), '1\n2\n')
154 self.assertEqual(self.isp._buffer, [])
154 self.assertEqual(self.isp._buffer, [])
155 self.assertEqual(self.isp.source, '')
155 self.assertEqual(self.isp.source, '')
156
156
157 def test_indent(self):
157 def test_indent(self):
158 isp = self.isp # shorthand
158 isp = self.isp # shorthand
159 isp.push('x=1')
159 isp.push('x=1')
160 self.assertEqual(isp.indent_spaces, 0)
160 self.assertEqual(isp.indent_spaces, 0)
161 isp.push('if 1:\n x=1')
161 isp.push('if 1:\n x=1')
162 self.assertEqual(isp.indent_spaces, 4)
162 self.assertEqual(isp.indent_spaces, 4)
163 isp.push('y=2\n')
163 isp.push('y=2\n')
164 self.assertEqual(isp.indent_spaces, 0)
164 self.assertEqual(isp.indent_spaces, 0)
165 isp.push('if 1:')
165 isp.push('if 1:')
166 self.assertEqual(isp.indent_spaces, 4)
166 self.assertEqual(isp.indent_spaces, 4)
167 isp.push(' x=1')
167 isp.push(' x=1')
168 self.assertEqual(isp.indent_spaces, 4)
168 self.assertEqual(isp.indent_spaces, 4)
169 # Blank lines shouldn't change the indent level
169 # Blank lines shouldn't change the indent level
170 isp.push(' '*2)
170 isp.push(' '*2)
171 self.assertEqual(isp.indent_spaces, 4)
171 self.assertEqual(isp.indent_spaces, 4)
172
172
173 def test_indent2(self):
173 def test_indent2(self):
174 isp = self.isp
174 isp = self.isp
175 # When a multiline statement contains parens or multiline strings, we
175 # When a multiline statement contains parens or multiline strings, we
176 # shouldn't get confused.
176 # shouldn't get confused.
177 isp.push("if 1:")
177 isp.push("if 1:")
178 isp.push(" x = (1+\n 2)")
178 isp.push(" x = (1+\n 2)")
179 self.assertEqual(isp.indent_spaces, 4)
179 self.assertEqual(isp.indent_spaces, 4)
180
180
181 def test_dedent(self):
181 def test_dedent(self):
182 isp = self.isp # shorthand
182 isp = self.isp # shorthand
183 isp.push('if 1:')
183 isp.push('if 1:')
184 self.assertEqual(isp.indent_spaces, 4)
184 self.assertEqual(isp.indent_spaces, 4)
185 isp.push(' pass')
185 isp.push(' pass')
186 self.assertEqual(isp.indent_spaces, 0)
186 self.assertEqual(isp.indent_spaces, 0)
187
187
188 def test_push(self):
188 def test_push(self):
189 isp = self.isp
189 isp = self.isp
190 self.assertTrue(isp.push('x=1'))
190 self.assertTrue(isp.push('x=1'))
191
191
192 def test_push2(self):
192 def test_push2(self):
193 isp = self.isp
193 isp = self.isp
194 self.assertFalse(isp.push('if 1:'))
194 self.assertFalse(isp.push('if 1:'))
195 for line in [' x=1', '# a comment', ' y=2']:
195 for line in [' x=1', '# a comment', ' y=2']:
196 self.assertTrue(isp.push(line))
196 self.assertTrue(isp.push(line))
197
197
198 def test_push3(self):
198 def test_push3(self):
199 """Test input with leading whitespace"""
199 """Test input with leading whitespace"""
200 isp = self.isp
200 isp = self.isp
201 isp.push(' x=1')
201 isp.push(' x=1')
202 isp.push(' y=2')
202 isp.push(' y=2')
203 self.assertEqual(isp.source, 'if 1:\n x=1\n y=2\n')
203 self.assertEqual(isp.source, 'if 1:\n x=1\n y=2\n')
204
204
205 def test_replace_mode(self):
205 def test_replace_mode(self):
206 isp = self.isp
206 isp = self.isp
207 isp.input_mode = 'cell'
207 isp.input_mode = 'cell'
208 isp.push('x=1')
208 isp.push('x=1')
209 self.assertEqual(isp.source, 'x=1\n')
209 self.assertEqual(isp.source, 'x=1\n')
210 isp.push('x=2')
210 isp.push('x=2')
211 self.assertEqual(isp.source, 'x=2\n')
211 self.assertEqual(isp.source, 'x=2\n')
212
212
213 def test_push_accepts_more(self):
213 def test_push_accepts_more(self):
214 isp = self.isp
214 isp = self.isp
215 isp.push('x=1')
215 isp.push('x=1')
216 self.assertFalse(isp.push_accepts_more())
216 self.assertFalse(isp.push_accepts_more())
217
217
218 def test_push_accepts_more2(self):
218 def test_push_accepts_more2(self):
219 isp = self.isp
219 isp = self.isp
220 isp.push('if 1:')
220 isp.push('if 1:')
221 self.assertTrue(isp.push_accepts_more())
221 self.assertTrue(isp.push_accepts_more())
222 isp.push(' x=1')
222 isp.push(' x=1')
223 self.assertTrue(isp.push_accepts_more())
223 self.assertTrue(isp.push_accepts_more())
224 isp.push('')
224 isp.push('')
225 self.assertFalse(isp.push_accepts_more())
225 self.assertFalse(isp.push_accepts_more())
226
226
227 def test_push_accepts_more3(self):
227 def test_push_accepts_more3(self):
228 isp = self.isp
228 isp = self.isp
229 isp.push("x = (2+\n3)")
229 isp.push("x = (2+\n3)")
230 self.assertFalse(isp.push_accepts_more())
230 self.assertFalse(isp.push_accepts_more())
231
231
232 def test_push_accepts_more4(self):
232 def test_push_accepts_more4(self):
233 isp = self.isp
233 isp = self.isp
234 # When a multiline statement contains parens or multiline strings, we
234 # When a multiline statement contains parens or multiline strings, we
235 # shouldn't get confused.
235 # shouldn't get confused.
236 # FIXME: we should be able to better handle de-dents in statements like
236 # FIXME: we should be able to better handle de-dents in statements like
237 # multiline strings and multiline expressions (continued with \ or
237 # multiline strings and multiline expressions (continued with \ or
238 # parens). Right now we aren't handling the indentation tracking quite
238 # parens). Right now we aren't handling the indentation tracking quite
239 # correctly with this, though in practice it may not be too much of a
239 # correctly with this, though in practice it may not be too much of a
240 # problem. We'll need to see.
240 # problem. We'll need to see.
241 isp.push("if 1:")
241 isp.push("if 1:")
242 isp.push(" x = (2+")
242 isp.push(" x = (2+")
243 isp.push(" 3)")
243 isp.push(" 3)")
244 self.assertTrue(isp.push_accepts_more())
244 self.assertTrue(isp.push_accepts_more())
245 isp.push(" y = 3")
245 isp.push(" y = 3")
246 self.assertTrue(isp.push_accepts_more())
246 self.assertTrue(isp.push_accepts_more())
247 isp.push('')
247 isp.push('')
248 self.assertFalse(isp.push_accepts_more())
248 self.assertFalse(isp.push_accepts_more())
249
249
250 def test_continuation(self):
250 def test_continuation(self):
251 isp = self.isp
251 isp = self.isp
252 isp.push("import os, \\")
252 isp.push("import os, \\")
253 self.assertTrue(isp.push_accepts_more())
253 self.assertTrue(isp.push_accepts_more())
254 isp.push("sys")
254 isp.push("sys")
255 self.assertFalse(isp.push_accepts_more())
255 self.assertFalse(isp.push_accepts_more())
256
256
257 def test_syntax_error(self):
257 def test_syntax_error(self):
258 isp = self.isp
258 isp = self.isp
259 # Syntax errors immediately produce a 'ready' block, so the invalid
259 # Syntax errors immediately produce a 'ready' block, so the invalid
260 # Python can be sent to the kernel for evaluation with possible ipython
260 # Python can be sent to the kernel for evaluation with possible ipython
261 # special-syntax conversion.
261 # special-syntax conversion.
262 isp.push('run foo')
262 isp.push('run foo')
263 self.assertFalse(isp.push_accepts_more())
263 self.assertFalse(isp.push_accepts_more())
264
264
265 def check_split(self, block_lines, compile=True):
265 def check_split(self, block_lines, compile=True):
266 blocks = assemble(block_lines)
266 blocks = assemble(block_lines)
267 lines = ''.join(blocks)
267 lines = ''.join(blocks)
268 oblock = self.isp.split_blocks(lines)
268 oblock = self.isp.split_blocks(lines)
269 self.assertEqual(oblock, blocks)
269 self.assertEqual(oblock, blocks)
270 if compile:
270 if compile:
271 for block in blocks:
271 for block in blocks:
272 self.isp._compile(block)
272 self.isp._compile(block)
273
273
274 def test_split(self):
274 def test_split(self):
275 # All blocks of input we want to test in a list. The format for each
275 # All blocks of input we want to test in a list. The format for each
276 # block is a list of lists, with each inner lists consisting of all the
276 # block is a list of lists, with each inner lists consisting of all the
277 # lines (as single-lines) that should make up a sub-block.
277 # lines (as single-lines) that should make up a sub-block.
278
278
279 # Note: do NOT put here sub-blocks that don't compile, as the
279 # Note: do NOT put here sub-blocks that don't compile, as the
280 # check_split() routine makes a final verification pass to check that
280 # check_split() routine makes a final verification pass to check that
281 # each sub_block, as returned by split_blocks(), does compile
281 # each sub_block, as returned by split_blocks(), does compile
282 # correctly.
282 # correctly.
283 all_blocks = [ [['x=1']],
283 all_blocks = [ [['x=1']],
284
284
285 [['x=1'],
285 [['x=1'],
286 ['y=2']],
286 ['y=2']],
287
287
288 [['x=1',
288 [['x=1',
289 '# a comment'],
289 '# a comment'],
290 ['y=11']],
290 ['y=11']],
291
291
292 [['if 1:',
292 [['if 1:',
293 ' x=1'],
293 ' x=1'],
294 ['y=3']],
294 ['y=3']],
295
295
296 [['def f(x):',
296 [['def f(x):',
297 ' return x'],
297 ' return x'],
298 ['x=1']],
298 ['x=1']],
299
299
300 [['def f(x):',
300 [['def f(x):',
301 ' x+=1',
301 ' x+=1',
302 ' ',
302 ' ',
303 ' return x'],
303 ' return x'],
304 ['x=1']],
304 ['x=1']],
305
305
306 [['def f(x):',
306 [['def f(x):',
307 ' if x>0:',
307 ' if x>0:',
308 ' y=1',
308 ' y=1',
309 ' # a comment',
309 ' # a comment',
310 ' else:',
310 ' else:',
311 ' y=4',
311 ' y=4',
312 ' ',
312 ' ',
313 ' return y'],
313 ' return y'],
314 ['x=1'],
314 ['x=1'],
315 ['if 1:',
315 ['if 1:',
316 ' y=11'] ],
316 ' y=11'] ],
317
317
318 [['for i in range(10):'
318 [['for i in range(10):'
319 ' x=i**2']],
319 ' x=i**2']],
320
320
321 [['for i in range(10):'
321 [['for i in range(10):'
322 ' x=i**2'],
322 ' x=i**2'],
323 ['z = 1']],
323 ['z = 1']],
324 ]
324 ]
325 for block_lines in all_blocks:
325 for block_lines in all_blocks:
326 self.check_split(block_lines)
326 self.check_split(block_lines)
327
327
328 def test_split_syntax_errors(self):
328 def test_split_syntax_errors(self):
329 # Block splitting with invalid syntax
329 # Block splitting with invalid syntax
330 all_blocks = [ [['a syntax error']],
330 all_blocks = [ [['a syntax error']],
331
331
332 [['x=1',
332 [['x=1',
333 'another syntax error']],
333 'another syntax error']],
334
334
335 [['for i in range(10):'
335 [['for i in range(10):'
336 ' yet another error']],
336 ' yet another error']],
337
337
338 ]
338 ]
339 for block_lines in all_blocks:
339 for block_lines in all_blocks:
340 self.check_split(block_lines, compile=False)
340 self.check_split(block_lines, compile=False)
341
341
342
342
343 class InteractiveLoopTestCase(unittest.TestCase):
343 class InteractiveLoopTestCase(unittest.TestCase):
344 """Tests for an interactive loop like a python shell.
344 """Tests for an interactive loop like a python shell.
345 """
345 """
346 def check_ns(self, lines, ns):
346 def check_ns(self, lines, ns):
347 """Validate that the given input lines produce the resulting namespace.
347 """Validate that the given input lines produce the resulting namespace.
348
348
349 Note: the input lines are given exactly as they would be typed in an
349 Note: the input lines are given exactly as they would be typed in an
350 auto-indenting environment, as mini_interactive_loop above already does
350 auto-indenting environment, as mini_interactive_loop above already does
351 auto-indenting and prepends spaces to the input.
351 auto-indenting and prepends spaces to the input.
352 """
352 """
353 src = mini_interactive_loop(pseudo_input(lines))
353 src = mini_interactive_loop(pseudo_input(lines))
354 test_ns = {}
354 test_ns = {}
355 exec src in test_ns
355 exec src in test_ns
356 # We can't check that the provided ns is identical to the test_ns,
356 # We can't check that the provided ns is identical to the test_ns,
357 # because Python fills test_ns with extra keys (copyright, etc). But
357 # because Python fills test_ns with extra keys (copyright, etc). But
358 # we can check that the given dict is *contained* in test_ns
358 # we can check that the given dict is *contained* in test_ns
359 for k,v in ns.items():
359 for k,v in ns.iteritems():
360 self.assertEqual(test_ns[k], v)
360 self.assertEqual(test_ns[k], v)
361
361
362 def test_simple(self):
362 def test_simple(self):
363 self.check_ns(['x=1'], dict(x=1))
363 self.check_ns(['x=1'], dict(x=1))
364
364
365 def test_simple2(self):
365 def test_simple2(self):
366 self.check_ns(['if 1:', 'x=2'], dict(x=2))
366 self.check_ns(['if 1:', 'x=2'], dict(x=2))
367
367
368 def test_xy(self):
368 def test_xy(self):
369 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
369 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
370
370
371 def test_abc(self):
371 def test_abc(self):
372 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
372 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
373
373
374 def test_multi(self):
374 def test_multi(self):
375 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
375 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
376
376
377
377
378 def test_LineInfo():
378 def test_LineInfo():
379 """Simple test for LineInfo construction and str()"""
379 """Simple test for LineInfo construction and str()"""
380 linfo = isp.LineInfo(' %cd /home')
380 linfo = isp.LineInfo(' %cd /home')
381 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
381 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
382
382
383
383
384 def test_split_user_input():
384 def test_split_user_input():
385 """Unicode test - split_user_input already has good doctests"""
385 """Unicode test - split_user_input already has good doctests"""
386 line = u"PΓ©rez Fernando"
386 line = u"PΓ©rez Fernando"
387 parts = isp.split_user_input(line)
387 parts = isp.split_user_input(line)
388 parts_expected = (u'', u'', u'', line)
388 parts_expected = (u'', u'', u'', line)
389 nt.assert_equal(parts, parts_expected)
389 nt.assert_equal(parts, parts_expected)
390
390
391
391
392 # Transformer tests
392 # Transformer tests
393 def transform_checker(tests, func):
393 def transform_checker(tests, func):
394 """Utility to loop over test inputs"""
394 """Utility to loop over test inputs"""
395 for inp, tr in tests:
395 for inp, tr in tests:
396 nt.assert_equals(func(inp), tr)
396 nt.assert_equals(func(inp), tr)
397
397
398 # Data for all the syntax tests in the form of lists of pairs of
398 # Data for all the syntax tests in the form of lists of pairs of
399 # raw/transformed input. We store it here as a global dict so that we can use
399 # raw/transformed input. We store it here as a global dict so that we can use
400 # it both within single-function tests and also to validate the behavior of the
400 # it both within single-function tests and also to validate the behavior of the
401 # larger objects
401 # larger objects
402
402
403 syntax = \
403 syntax = \
404 dict(assign_system =
404 dict(assign_system =
405 [('a =! ls', 'a = get_ipython().getoutput("ls")'),
405 [('a =! ls', 'a = get_ipython().getoutput("ls")'),
406 ('b = !ls', 'b = get_ipython().getoutput("ls")'),
406 ('b = !ls', 'b = get_ipython().getoutput("ls")'),
407 ('x=1', 'x=1'), # normal input is unmodified
407 ('x=1', 'x=1'), # normal input is unmodified
408 (' ',' '), # blank lines are kept intact
408 (' ',' '), # blank lines are kept intact
409 ],
409 ],
410
410
411 assign_magic =
411 assign_magic =
412 [('a =% who', 'a = get_ipython().magic("who")'),
412 [('a =% who', 'a = get_ipython().magic("who")'),
413 ('b = %who', 'b = get_ipython().magic("who")'),
413 ('b = %who', 'b = get_ipython().magic("who")'),
414 ('x=1', 'x=1'), # normal input is unmodified
414 ('x=1', 'x=1'), # normal input is unmodified
415 (' ',' '), # blank lines are kept intact
415 (' ',' '), # blank lines are kept intact
416 ],
416 ],
417
417
418 classic_prompt =
418 classic_prompt =
419 [('>>> x=1', 'x=1'),
419 [('>>> x=1', 'x=1'),
420 ('x=1', 'x=1'), # normal input is unmodified
420 ('x=1', 'x=1'), # normal input is unmodified
421 (' ', ' '), # blank lines are kept intact
421 (' ', ' '), # blank lines are kept intact
422 ('... ', ''), # continuation prompts
422 ('... ', ''), # continuation prompts
423 ],
423 ],
424
424
425 ipy_prompt =
425 ipy_prompt =
426 [('In [1]: x=1', 'x=1'),
426 [('In [1]: x=1', 'x=1'),
427 ('x=1', 'x=1'), # normal input is unmodified
427 ('x=1', 'x=1'), # normal input is unmodified
428 (' ',' '), # blank lines are kept intact
428 (' ',' '), # blank lines are kept intact
429 (' ....: ', ''), # continuation prompts
429 (' ....: ', ''), # continuation prompts
430 ],
430 ],
431
431
432 # Tests for the escape transformer to leave normal code alone
432 # Tests for the escape transformer to leave normal code alone
433 escaped_noesc =
433 escaped_noesc =
434 [ (' ', ' '),
434 [ (' ', ' '),
435 ('x=1', 'x=1'),
435 ('x=1', 'x=1'),
436 ],
436 ],
437
437
438 # System calls
438 # System calls
439 escaped_shell =
439 escaped_shell =
440 [ ('!ls', 'get_ipython().system("ls")'),
440 [ ('!ls', 'get_ipython().system("ls")'),
441 # Double-escape shell, this means to capture the output of the
441 # Double-escape shell, this means to capture the output of the
442 # subprocess and return it
442 # subprocess and return it
443 ('!!ls', 'get_ipython().getoutput("ls")'),
443 ('!!ls', 'get_ipython().getoutput("ls")'),
444 ],
444 ],
445
445
446 # Help/object info
446 # Help/object info
447 escaped_help =
447 escaped_help =
448 [ ('?', 'get_ipython().show_usage()'),
448 [ ('?', 'get_ipython().show_usage()'),
449 ('?x1', 'get_ipython().magic("pinfo x1")'),
449 ('?x1', 'get_ipython().magic("pinfo x1")'),
450 ('??x2', 'get_ipython().magic("pinfo2 x2")'),
450 ('??x2', 'get_ipython().magic("pinfo2 x2")'),
451 ('x3?', 'get_ipython().magic("pinfo x3")'),
451 ('x3?', 'get_ipython().magic("pinfo x3")'),
452 ('x4??', 'get_ipython().magic("pinfo2 x4")'),
452 ('x4??', 'get_ipython().magic("pinfo2 x4")'),
453 ('%hist?', 'get_ipython().magic("pinfo %hist")'),
453 ('%hist?', 'get_ipython().magic("pinfo %hist")'),
454 ('f*?', 'get_ipython().magic("psearch f*")'),
454 ('f*?', 'get_ipython().magic("psearch f*")'),
455 ('ax.*aspe*?', 'get_ipython().magic("psearch ax.*aspe*")'),
455 ('ax.*aspe*?', 'get_ipython().magic("psearch ax.*aspe*")'),
456 ],
456 ],
457
457
458 # Explicit magic calls
458 # Explicit magic calls
459 escaped_magic =
459 escaped_magic =
460 [ ('%cd', 'get_ipython().magic("cd")'),
460 [ ('%cd', 'get_ipython().magic("cd")'),
461 ('%cd /home', 'get_ipython().magic("cd /home")'),
461 ('%cd /home', 'get_ipython().magic("cd /home")'),
462 (' %magic', ' get_ipython().magic("magic")'),
462 (' %magic', ' get_ipython().magic("magic")'),
463 ],
463 ],
464
464
465 # Quoting with separate arguments
465 # Quoting with separate arguments
466 escaped_quote =
466 escaped_quote =
467 [ (',f', 'f("")'),
467 [ (',f', 'f("")'),
468 (',f x', 'f("x")'),
468 (',f x', 'f("x")'),
469 (' ,f y', ' f("y")'),
469 (' ,f y', ' f("y")'),
470 (',f a b', 'f("a", "b")'),
470 (',f a b', 'f("a", "b")'),
471 ],
471 ],
472
472
473 # Quoting with single argument
473 # Quoting with single argument
474 escaped_quote2 =
474 escaped_quote2 =
475 [ (';f', 'f("")'),
475 [ (';f', 'f("")'),
476 (';f x', 'f("x")'),
476 (';f x', 'f("x")'),
477 (' ;f y', ' f("y")'),
477 (' ;f y', ' f("y")'),
478 (';f a b', 'f("a b")'),
478 (';f a b', 'f("a b")'),
479 ],
479 ],
480
480
481 # Simply apply parens
481 # Simply apply parens
482 escaped_paren =
482 escaped_paren =
483 [ ('/f', 'f()'),
483 [ ('/f', 'f()'),
484 ('/f x', 'f(x)'),
484 ('/f x', 'f(x)'),
485 (' /f y', ' f(y)'),
485 (' /f y', ' f(y)'),
486 ('/f a b', 'f(a, b)'),
486 ('/f a b', 'f(a, b)'),
487 ],
487 ],
488
488
489 )
489 )
490
490
491 # multiline syntax examples. Each of these should be a list of lists, with
491 # multiline syntax examples. Each of these should be a list of lists, with
492 # each entry itself having pairs of raw/transformed input. The union (with
492 # each entry itself having pairs of raw/transformed input. The union (with
493 # '\n'.join() of the transformed inputs is what the splitter should produce
493 # '\n'.join() of the transformed inputs is what the splitter should produce
494 # when fed the raw lines one at a time via push.
494 # when fed the raw lines one at a time via push.
495 syntax_ml = \
495 syntax_ml = \
496 dict(classic_prompt =
496 dict(classic_prompt =
497 [ [('>>> for i in range(10):','for i in range(10):'),
497 [ [('>>> for i in range(10):','for i in range(10):'),
498 ('... print i',' print i'),
498 ('... print i',' print i'),
499 ('... ', ''),
499 ('... ', ''),
500 ],
500 ],
501 ],
501 ],
502
502
503 ipy_prompt =
503 ipy_prompt =
504 [ [('In [24]: for i in range(10):','for i in range(10):'),
504 [ [('In [24]: for i in range(10):','for i in range(10):'),
505 (' ....: print i',' print i'),
505 (' ....: print i',' print i'),
506 (' ....: ', ''),
506 (' ....: ', ''),
507 ],
507 ],
508 ],
508 ],
509 )
509 )
510
510
511
511
512 def test_assign_system():
512 def test_assign_system():
513 transform_checker(syntax['assign_system'], isp.transform_assign_system)
513 transform_checker(syntax['assign_system'], isp.transform_assign_system)
514
514
515
515
516 def test_assign_magic():
516 def test_assign_magic():
517 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
517 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
518
518
519
519
520 def test_classic_prompt():
520 def test_classic_prompt():
521 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
521 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
522 for example in syntax_ml['classic_prompt']:
522 for example in syntax_ml['classic_prompt']:
523 transform_checker(example, isp.transform_classic_prompt)
523 transform_checker(example, isp.transform_classic_prompt)
524
524
525
525
526 def test_ipy_prompt():
526 def test_ipy_prompt():
527 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
527 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
528 for example in syntax_ml['ipy_prompt']:
528 for example in syntax_ml['ipy_prompt']:
529 transform_checker(example, isp.transform_ipy_prompt)
529 transform_checker(example, isp.transform_ipy_prompt)
530
530
531
531
532 def test_escaped_noesc():
532 def test_escaped_noesc():
533 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
533 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
534
534
535
535
536 def test_escaped_shell():
536 def test_escaped_shell():
537 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
537 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
538
538
539
539
540 def test_escaped_help():
540 def test_escaped_help():
541 transform_checker(syntax['escaped_help'], isp.transform_escaped)
541 transform_checker(syntax['escaped_help'], isp.transform_escaped)
542
542
543
543
544 def test_escaped_magic():
544 def test_escaped_magic():
545 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
545 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
546
546
547
547
548 def test_escaped_quote():
548 def test_escaped_quote():
549 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
549 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
550
550
551
551
552 def test_escaped_quote2():
552 def test_escaped_quote2():
553 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
553 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
554
554
555
555
556 def test_escaped_paren():
556 def test_escaped_paren():
557 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
557 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
558
558
559
559
560 class IPythonInputTestCase(InputSplitterTestCase):
560 class IPythonInputTestCase(InputSplitterTestCase):
561 """By just creating a new class whose .isp is a different instance, we
561 """By just creating a new class whose .isp is a different instance, we
562 re-run the same test battery on the new input splitter.
562 re-run the same test battery on the new input splitter.
563
563
564 In addition, this runs the tests over the syntax and syntax_ml dicts that
564 In addition, this runs the tests over the syntax and syntax_ml dicts that
565 were tested by individual functions, as part of the OO interface.
565 were tested by individual functions, as part of the OO interface.
566 """
566 """
567
567
568 def setUp(self):
568 def setUp(self):
569 self.isp = isp.IPythonInputSplitter(input_mode='line')
569 self.isp = isp.IPythonInputSplitter(input_mode='line')
570
570
571 def test_syntax(self):
571 def test_syntax(self):
572 """Call all single-line syntax tests from the main object"""
572 """Call all single-line syntax tests from the main object"""
573 isp = self.isp
573 isp = self.isp
574 for example in syntax.itervalues():
574 for example in syntax.itervalues():
575 for raw, out_t in example:
575 for raw, out_t in example:
576 if raw.startswith(' '):
576 if raw.startswith(' '):
577 continue
577 continue
578
578
579 isp.push(raw)
579 isp.push(raw)
580 out = isp.source_reset().rstrip()
580 out = isp.source_reset().rstrip()
581 self.assertEqual(out, out_t)
581 self.assertEqual(out, out_t)
582
582
583 def test_syntax_multiline(self):
583 def test_syntax_multiline(self):
584 isp = self.isp
584 isp = self.isp
585 for example in syntax_ml.itervalues():
585 for example in syntax_ml.itervalues():
586 out_t_parts = []
586 out_t_parts = []
587 for line_pairs in example:
587 for line_pairs in example:
588 for raw, out_t_part in line_pairs:
588 for raw, out_t_part in line_pairs:
589 isp.push(raw)
589 isp.push(raw)
590 out_t_parts.append(out_t_part)
590 out_t_parts.append(out_t_part)
591
591
592 out = isp.source_reset().rstrip()
592 out = isp.source_reset().rstrip()
593 out_t = '\n'.join(out_t_parts).rstrip()
593 out_t = '\n'.join(out_t_parts).rstrip()
594 self.assertEqual(out, out_t)
594 self.assertEqual(out, out_t)
595
595
596
596
597 class BlockIPythonInputTestCase(IPythonInputTestCase):
597 class BlockIPythonInputTestCase(IPythonInputTestCase):
598
598
599 # Deactivate tests that don't make sense for the block mode
599 # Deactivate tests that don't make sense for the block mode
600 test_push3 = test_split = lambda s: None
600 test_push3 = test_split = lambda s: None
601
601
602 def setUp(self):
602 def setUp(self):
603 self.isp = isp.IPythonInputSplitter(input_mode='cell')
603 self.isp = isp.IPythonInputSplitter(input_mode='cell')
604
604
605 def test_syntax_multiline(self):
605 def test_syntax_multiline(self):
606 isp = self.isp
606 isp = self.isp
607 for example in syntax_ml.itervalues():
607 for example in syntax_ml.itervalues():
608 raw_parts = []
608 raw_parts = []
609 out_t_parts = []
609 out_t_parts = []
610 for line_pairs in example:
610 for line_pairs in example:
611 for raw, out_t_part in line_pairs:
611 for raw, out_t_part in line_pairs:
612 raw_parts.append(raw)
612 raw_parts.append(raw)
613 out_t_parts.append(out_t_part)
613 out_t_parts.append(out_t_part)
614
614
615 raw = '\n'.join(raw_parts)
615 raw = '\n'.join(raw_parts)
616 out_t = '\n'.join(out_t_parts)
616 out_t = '\n'.join(out_t_parts)
617
617
618 isp.push(raw)
618 isp.push(raw)
619 out = isp.source_reset()
619 out = isp.source_reset()
620 # Match ignoring trailing whitespace
620 # Match ignoring trailing whitespace
621 self.assertEqual(out.rstrip(), out_t.rstrip())
621 self.assertEqual(out.rstrip(), out_t.rstrip())
622
622
623
623
624 #-----------------------------------------------------------------------------
624 #-----------------------------------------------------------------------------
625 # Main - use as a script, mostly for developer experiments
625 # Main - use as a script, mostly for developer experiments
626 #-----------------------------------------------------------------------------
626 #-----------------------------------------------------------------------------
627
627
628 if __name__ == '__main__':
628 if __name__ == '__main__':
629 # A simple demo for interactive experimentation. This code will not get
629 # A simple demo for interactive experimentation. This code will not get
630 # picked up by any test suite.
630 # picked up by any test suite.
631 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
631 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
632
632
633 # configure here the syntax to use, prompt and whether to autoindent
633 # configure here the syntax to use, prompt and whether to autoindent
634 #isp, start_prompt = InputSplitter(), '>>> '
634 #isp, start_prompt = InputSplitter(), '>>> '
635 isp, start_prompt = IPythonInputSplitter(), 'In> '
635 isp, start_prompt = IPythonInputSplitter(), 'In> '
636
636
637 autoindent = True
637 autoindent = True
638 #autoindent = False
638 #autoindent = False
639
639
640 try:
640 try:
641 while True:
641 while True:
642 prompt = start_prompt
642 prompt = start_prompt
643 while isp.push_accepts_more():
643 while isp.push_accepts_more():
644 indent = ' '*isp.indent_spaces
644 indent = ' '*isp.indent_spaces
645 if autoindent:
645 if autoindent:
646 line = indent + raw_input(prompt+indent)
646 line = indent + raw_input(prompt+indent)
647 else:
647 else:
648 line = raw_input(prompt)
648 line = raw_input(prompt)
649 isp.push(line)
649 isp.push(line)
650 prompt = '... '
650 prompt = '... '
651
651
652 # Here we just return input so we can use it in a test suite, but a
652 # Here we just return input so we can use it in a test suite, but a
653 # real interpreter would instead send it for execution somewhere.
653 # real interpreter would instead send it for execution somewhere.
654 #src = isp.source; raise EOFError # dbg
654 #src = isp.source; raise EOFError # dbg
655 src = isp.source_reset()
655 src = isp.source_reset()
656 print 'Input source was:\n', src
656 print 'Input source was:\n', src
657 except EOFError:
657 except EOFError:
658 print 'Bye'
658 print 'Bye'
@@ -1,357 +1,357 b''
1 """Tests for various magic functions.
1 """Tests for various magic functions.
2
2
3 Needs to be run by nose (to make ipython session available).
3 Needs to be run by nose (to make ipython session available).
4 """
4 """
5 from __future__ import absolute_import
5 from __future__ import absolute_import
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Imports
8 # Imports
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 import os
11 import os
12 import sys
12 import sys
13 import tempfile
13 import tempfile
14 import types
14 import types
15 from cStringIO import StringIO
15 from cStringIO import StringIO
16
16
17 import nose.tools as nt
17 import nose.tools as nt
18
18
19 from IPython.utils.path import get_long_path_name
19 from IPython.utils.path import get_long_path_name
20 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
21 from IPython.testing import tools as tt
21 from IPython.testing import tools as tt
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Test functions begin
24 # Test functions begin
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 def test_rehashx():
26 def test_rehashx():
27 # clear up everything
27 # clear up everything
28 _ip = get_ipython()
28 _ip = get_ipython()
29 _ip.alias_manager.alias_table.clear()
29 _ip.alias_manager.alias_table.clear()
30 del _ip.db['syscmdlist']
30 del _ip.db['syscmdlist']
31
31
32 _ip.magic('rehashx')
32 _ip.magic('rehashx')
33 # Practically ALL ipython development systems will have more than 10 aliases
33 # Practically ALL ipython development systems will have more than 10 aliases
34
34
35 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
35 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
36 for key, val in _ip.alias_manager.alias_table.items():
36 for key, val in _ip.alias_manager.alias_table.iteritems():
37 # we must strip dots from alias names
37 # we must strip dots from alias names
38 nt.assert_true('.' not in key)
38 nt.assert_true('.' not in key)
39
39
40 # rehashx must fill up syscmdlist
40 # rehashx must fill up syscmdlist
41 scoms = _ip.db['syscmdlist']
41 scoms = _ip.db['syscmdlist']
42 yield (nt.assert_true, len(scoms) > 10)
42 yield (nt.assert_true, len(scoms) > 10)
43
43
44
44
45 def test_magic_parse_options():
45 def test_magic_parse_options():
46 """Test that we don't mangle paths when parsing magic options."""
46 """Test that we don't mangle paths when parsing magic options."""
47 ip = get_ipython()
47 ip = get_ipython()
48 path = 'c:\\x'
48 path = 'c:\\x'
49 opts = ip.parse_options('-f %s' % path,'f:')[0]
49 opts = ip.parse_options('-f %s' % path,'f:')[0]
50 # argv splitting is os-dependent
50 # argv splitting is os-dependent
51 if os.name == 'posix':
51 if os.name == 'posix':
52 expected = 'c:x'
52 expected = 'c:x'
53 else:
53 else:
54 expected = path
54 expected = path
55 nt.assert_equals(opts['f'], expected)
55 nt.assert_equals(opts['f'], expected)
56
56
57
57
58 def doctest_hist_f():
58 def doctest_hist_f():
59 """Test %hist -f with temporary filename.
59 """Test %hist -f with temporary filename.
60
60
61 In [9]: import tempfile
61 In [9]: import tempfile
62
62
63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
64
64
65 In [11]: %hist -n -f $tfile 3
65 In [11]: %hist -n -f $tfile 3
66
66
67 In [13]: import os; os.unlink(tfile)
67 In [13]: import os; os.unlink(tfile)
68 """
68 """
69
69
70
70
71 def doctest_hist_r():
71 def doctest_hist_r():
72 """Test %hist -r
72 """Test %hist -r
73
73
74 XXX - This test is not recording the output correctly. For some reason, in
74 XXX - This test is not recording the output correctly. For some reason, in
75 testing mode the raw history isn't getting populated. No idea why.
75 testing mode the raw history isn't getting populated. No idea why.
76 Disabling the output checking for now, though at least we do run it.
76 Disabling the output checking for now, though at least we do run it.
77
77
78 In [1]: 'hist' in _ip.lsmagic()
78 In [1]: 'hist' in _ip.lsmagic()
79 Out[1]: True
79 Out[1]: True
80
80
81 In [2]: x=1
81 In [2]: x=1
82
82
83 In [3]: %hist -r 2
83 In [3]: %hist -r 2
84 x=1 # random
84 x=1 # random
85 %hist -r 2
85 %hist -r 2
86 """
86 """
87
87
88 def doctest_hist_op():
88 def doctest_hist_op():
89 """Test %hist -op
89 """Test %hist -op
90
90
91 In [1]: class b:
91 In [1]: class b:
92 ...: pass
92 ...: pass
93 ...:
93 ...:
94
94
95 In [2]: class s(b):
95 In [2]: class s(b):
96 ...: def __str__(self):
96 ...: def __str__(self):
97 ...: return 's'
97 ...: return 's'
98 ...:
98 ...:
99
99
100 In [3]:
100 In [3]:
101
101
102 In [4]: class r(b):
102 In [4]: class r(b):
103 ...: def __repr__(self):
103 ...: def __repr__(self):
104 ...: return 'r'
104 ...: return 'r'
105 ...:
105 ...:
106
106
107 In [5]: class sr(s,r): pass
107 In [5]: class sr(s,r): pass
108 ...:
108 ...:
109
109
110 In [6]:
110 In [6]:
111
111
112 In [7]: bb=b()
112 In [7]: bb=b()
113
113
114 In [8]: ss=s()
114 In [8]: ss=s()
115
115
116 In [9]: rr=r()
116 In [9]: rr=r()
117
117
118 In [10]: ssrr=sr()
118 In [10]: ssrr=sr()
119
119
120 In [11]: bb
120 In [11]: bb
121 Out[11]: <...b instance at ...>
121 Out[11]: <...b instance at ...>
122
122
123 In [12]: ss
123 In [12]: ss
124 Out[12]: <...s instance at ...>
124 Out[12]: <...s instance at ...>
125
125
126 In [13]:
126 In [13]:
127
127
128 In [14]: %hist -op
128 In [14]: %hist -op
129 >>> class b:
129 >>> class b:
130 ... pass
130 ... pass
131 ...
131 ...
132 >>> class s(b):
132 >>> class s(b):
133 ... def __str__(self):
133 ... def __str__(self):
134 ... return 's'
134 ... return 's'
135 ...
135 ...
136 >>>
136 >>>
137 >>> class r(b):
137 >>> class r(b):
138 ... def __repr__(self):
138 ... def __repr__(self):
139 ... return 'r'
139 ... return 'r'
140 ...
140 ...
141 >>> class sr(s,r): pass
141 >>> class sr(s,r): pass
142 >>>
142 >>>
143 >>> bb=b()
143 >>> bb=b()
144 >>> ss=s()
144 >>> ss=s()
145 >>> rr=r()
145 >>> rr=r()
146 >>> ssrr=sr()
146 >>> ssrr=sr()
147 >>> bb
147 >>> bb
148 <...b instance at ...>
148 <...b instance at ...>
149 >>> ss
149 >>> ss
150 <...s instance at ...>
150 <...s instance at ...>
151 >>>
151 >>>
152 """
152 """
153
153
154 def test_shist():
154 def test_shist():
155 # Simple tests of ShadowHist class - test generator.
155 # Simple tests of ShadowHist class - test generator.
156 import os, shutil, tempfile
156 import os, shutil, tempfile
157
157
158 from IPython.utils import pickleshare
158 from IPython.utils import pickleshare
159 from IPython.core.history import ShadowHist
159 from IPython.core.history import ShadowHist
160
160
161 tfile = tempfile.mktemp('','tmp-ipython-')
161 tfile = tempfile.mktemp('','tmp-ipython-')
162
162
163 db = pickleshare.PickleShareDB(tfile)
163 db = pickleshare.PickleShareDB(tfile)
164 s = ShadowHist(db)
164 s = ShadowHist(db)
165 s.add('hello')
165 s.add('hello')
166 s.add('world')
166 s.add('world')
167 s.add('hello')
167 s.add('hello')
168 s.add('hello')
168 s.add('hello')
169 s.add('karhu')
169 s.add('karhu')
170
170
171 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
171 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
172
172
173 yield nt.assert_equal,s.get(2),'world'
173 yield nt.assert_equal,s.get(2),'world'
174
174
175 shutil.rmtree(tfile)
175 shutil.rmtree(tfile)
176
176
177
177
178 # XXX failing for now, until we get clearcmd out of quarantine. But we should
178 # XXX failing for now, until we get clearcmd out of quarantine. But we should
179 # fix this and revert the skip to happen only if numpy is not around.
179 # fix this and revert the skip to happen only if numpy is not around.
180 #@dec.skipif_not_numpy
180 #@dec.skipif_not_numpy
181 @dec.skip_known_failure
181 @dec.skip_known_failure
182 def test_numpy_clear_array_undec():
182 def test_numpy_clear_array_undec():
183 from IPython.extensions import clearcmd
183 from IPython.extensions import clearcmd
184
184
185 _ip.ex('import numpy as np')
185 _ip.ex('import numpy as np')
186 _ip.ex('a = np.empty(2)')
186 _ip.ex('a = np.empty(2)')
187 yield (nt.assert_true, 'a' in _ip.user_ns)
187 yield (nt.assert_true, 'a' in _ip.user_ns)
188 _ip.magic('clear array')
188 _ip.magic('clear array')
189 yield (nt.assert_false, 'a' in _ip.user_ns)
189 yield (nt.assert_false, 'a' in _ip.user_ns)
190
190
191
191
192 # Multiple tests for clipboard pasting
192 # Multiple tests for clipboard pasting
193 @dec.parametric
193 @dec.parametric
194 def test_paste():
194 def test_paste():
195 _ip = get_ipython()
195 _ip = get_ipython()
196 def paste(txt, flags='-q'):
196 def paste(txt, flags='-q'):
197 """Paste input text, by default in quiet mode"""
197 """Paste input text, by default in quiet mode"""
198 hooks.clipboard_get = lambda : txt
198 hooks.clipboard_get = lambda : txt
199 _ip.magic('paste '+flags)
199 _ip.magic('paste '+flags)
200
200
201 # Inject fake clipboard hook but save original so we can restore it later
201 # Inject fake clipboard hook but save original so we can restore it later
202 hooks = _ip.hooks
202 hooks = _ip.hooks
203 user_ns = _ip.user_ns
203 user_ns = _ip.user_ns
204 original_clip = hooks.clipboard_get
204 original_clip = hooks.clipboard_get
205
205
206 try:
206 try:
207 # This try/except with an emtpy except clause is here only because
207 # This try/except with an emtpy except clause is here only because
208 # try/yield/finally is invalid syntax in Python 2.4. This will be
208 # try/yield/finally is invalid syntax in Python 2.4. This will be
209 # removed when we drop 2.4-compatibility, and the emtpy except below
209 # removed when we drop 2.4-compatibility, and the emtpy except below
210 # will be changed to a finally.
210 # will be changed to a finally.
211
211
212 # Run tests with fake clipboard function
212 # Run tests with fake clipboard function
213 user_ns.pop('x', None)
213 user_ns.pop('x', None)
214 paste('x=1')
214 paste('x=1')
215 yield nt.assert_equal(user_ns['x'], 1)
215 yield nt.assert_equal(user_ns['x'], 1)
216
216
217 user_ns.pop('x', None)
217 user_ns.pop('x', None)
218 paste('>>> x=2')
218 paste('>>> x=2')
219 yield nt.assert_equal(user_ns['x'], 2)
219 yield nt.assert_equal(user_ns['x'], 2)
220
220
221 paste("""
221 paste("""
222 >>> x = [1,2,3]
222 >>> x = [1,2,3]
223 >>> y = []
223 >>> y = []
224 >>> for i in x:
224 >>> for i in x:
225 ... y.append(i**2)
225 ... y.append(i**2)
226 ...
226 ...
227 """)
227 """)
228 yield nt.assert_equal(user_ns['x'], [1,2,3])
228 yield nt.assert_equal(user_ns['x'], [1,2,3])
229 yield nt.assert_equal(user_ns['y'], [1,4,9])
229 yield nt.assert_equal(user_ns['y'], [1,4,9])
230
230
231 # Now, test that paste -r works
231 # Now, test that paste -r works
232 user_ns.pop('x', None)
232 user_ns.pop('x', None)
233 yield nt.assert_false('x' in user_ns)
233 yield nt.assert_false('x' in user_ns)
234 _ip.magic('paste -r')
234 _ip.magic('paste -r')
235 yield nt.assert_equal(user_ns['x'], [1,2,3])
235 yield nt.assert_equal(user_ns['x'], [1,2,3])
236
236
237 # Also test paste echoing, by temporarily faking the writer
237 # Also test paste echoing, by temporarily faking the writer
238 w = StringIO()
238 w = StringIO()
239 writer = _ip.write
239 writer = _ip.write
240 _ip.write = w.write
240 _ip.write = w.write
241 code = """
241 code = """
242 a = 100
242 a = 100
243 b = 200"""
243 b = 200"""
244 try:
244 try:
245 paste(code,'')
245 paste(code,'')
246 out = w.getvalue()
246 out = w.getvalue()
247 finally:
247 finally:
248 _ip.write = writer
248 _ip.write = writer
249 yield nt.assert_equal(user_ns['a'], 100)
249 yield nt.assert_equal(user_ns['a'], 100)
250 yield nt.assert_equal(user_ns['b'], 200)
250 yield nt.assert_equal(user_ns['b'], 200)
251 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
251 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
252
252
253 finally:
253 finally:
254 # This should be in a finally clause, instead of the bare except above.
254 # This should be in a finally clause, instead of the bare except above.
255 # Restore original hook
255 # Restore original hook
256 hooks.clipboard_get = original_clip
256 hooks.clipboard_get = original_clip
257
257
258
258
259 def test_time():
259 def test_time():
260 _ip.magic('time None')
260 _ip.magic('time None')
261
261
262
262
263 def doctest_time():
263 def doctest_time():
264 """
264 """
265 In [10]: %time None
265 In [10]: %time None
266 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
266 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
267 Wall time: 0.00 s
267 Wall time: 0.00 s
268 """
268 """
269
269
270
270
271 def test_doctest_mode():
271 def test_doctest_mode():
272 "Toggle doctest_mode twice, it should be a no-op and run without error"
272 "Toggle doctest_mode twice, it should be a no-op and run without error"
273 _ip.magic('doctest_mode')
273 _ip.magic('doctest_mode')
274 _ip.magic('doctest_mode')
274 _ip.magic('doctest_mode')
275
275
276
276
277 def test_parse_options():
277 def test_parse_options():
278 """Tests for basic options parsing in magics."""
278 """Tests for basic options parsing in magics."""
279 # These are only the most minimal of tests, more should be added later. At
279 # These are only the most minimal of tests, more should be added later. At
280 # the very least we check that basic text/unicode calls work OK.
280 # the very least we check that basic text/unicode calls work OK.
281 nt.assert_equal(_ip.parse_options('foo', '')[1], 'foo')
281 nt.assert_equal(_ip.parse_options('foo', '')[1], 'foo')
282 nt.assert_equal(_ip.parse_options(u'foo', '')[1], u'foo')
282 nt.assert_equal(_ip.parse_options(u'foo', '')[1], u'foo')
283
283
284
284
285 def test_dirops():
285 def test_dirops():
286 """Test various directory handling operations."""
286 """Test various directory handling operations."""
287 curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
287 curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
288
288
289 startdir = os.getcwd()
289 startdir = os.getcwd()
290 ipdir = _ip.ipython_dir
290 ipdir = _ip.ipython_dir
291 try:
291 try:
292 _ip.magic('cd "%s"' % ipdir)
292 _ip.magic('cd "%s"' % ipdir)
293 nt.assert_equal(curpath(), ipdir)
293 nt.assert_equal(curpath(), ipdir)
294 _ip.magic('cd -')
294 _ip.magic('cd -')
295 nt.assert_equal(curpath(), startdir)
295 nt.assert_equal(curpath(), startdir)
296 _ip.magic('pushd "%s"' % ipdir)
296 _ip.magic('pushd "%s"' % ipdir)
297 nt.assert_equal(curpath(), ipdir)
297 nt.assert_equal(curpath(), ipdir)
298 _ip.magic('popd')
298 _ip.magic('popd')
299 nt.assert_equal(curpath(), startdir)
299 nt.assert_equal(curpath(), startdir)
300 finally:
300 finally:
301 os.chdir(startdir)
301 os.chdir(startdir)
302
302
303
303
304 def check_cpaste(code, should_fail=False):
304 def check_cpaste(code, should_fail=False):
305 """Execute code via 'cpaste' and ensure it was executed, unless
305 """Execute code via 'cpaste' and ensure it was executed, unless
306 should_fail is set.
306 should_fail is set.
307 """
307 """
308 _ip.user_ns['code_ran'] = False
308 _ip.user_ns['code_ran'] = False
309
309
310 src = StringIO()
310 src = StringIO()
311 src.write('\n')
311 src.write('\n')
312 src.write(code)
312 src.write(code)
313 src.write('\n--\n')
313 src.write('\n--\n')
314 src.seek(0)
314 src.seek(0)
315
315
316 stdin_save = sys.stdin
316 stdin_save = sys.stdin
317 sys.stdin = src
317 sys.stdin = src
318
318
319 try:
319 try:
320 _ip.magic('cpaste')
320 _ip.magic('cpaste')
321 except:
321 except:
322 if not should_fail:
322 if not should_fail:
323 raise AssertionError("Failure not expected : '%s'" %
323 raise AssertionError("Failure not expected : '%s'" %
324 code)
324 code)
325 else:
325 else:
326 assert _ip.user_ns['code_ran']
326 assert _ip.user_ns['code_ran']
327 if should_fail:
327 if should_fail:
328 raise AssertionError("Failure expected : '%s'" % code)
328 raise AssertionError("Failure expected : '%s'" % code)
329 finally:
329 finally:
330 sys.stdin = stdin_save
330 sys.stdin = stdin_save
331
331
332
332
333 def test_cpaste():
333 def test_cpaste():
334 """Test cpaste magic"""
334 """Test cpaste magic"""
335
335
336 def run():
336 def run():
337 """Marker function: sets a flag when executed.
337 """Marker function: sets a flag when executed.
338 """
338 """
339 _ip.user_ns['code_ran'] = True
339 _ip.user_ns['code_ran'] = True
340 return 'run' # return string so '+ run()' doesn't result in success
340 return 'run' # return string so '+ run()' doesn't result in success
341
341
342 tests = {'pass': ["> > > run()",
342 tests = {'pass': ["> > > run()",
343 ">>> > run()",
343 ">>> > run()",
344 "+++ run()",
344 "+++ run()",
345 "++ run()",
345 "++ run()",
346 " >>> run()"],
346 " >>> run()"],
347
347
348 'fail': ["+ + run()",
348 'fail': ["+ + run()",
349 " ++ run()"]}
349 " ++ run()"]}
350
350
351 _ip.user_ns['run'] = run
351 _ip.user_ns['run'] = run
352
352
353 for code in tests['pass']:
353 for code in tests['pass']:
354 check_cpaste(code)
354 check_cpaste(code)
355
355
356 for code in tests['fail']:
356 for code in tests['fail']:
357 check_cpaste(code, should_fail=True)
357 check_cpaste(code, should_fail=True)
@@ -1,2501 +1,2472 b''
1 # -*- coding: utf-8 -*-
1 # configobj.py
2 # configobj.py
2 # A config file reader/writer that supports nested sections in config files.
3 # A config file reader/writer that supports nested sections in config files.
3 # Copyright (C) 2005-2008 Michael Foord, Nicola Larosa
4 # Copyright (C) 2005-2008 Michael Foord, Nicola Larosa
4 # E-mail: fuzzyman AT voidspace DOT org DOT uk
5 # E-mail: fuzzyman AT voidspace DOT org DOT uk
5 # nico AT tekNico DOT net
6 # nico AT tekNico DOT net
6
7
7 # ConfigObj 4
8 # ConfigObj 4
8 # http://www.voidspace.org.uk/python/configobj.html
9 # http://www.voidspace.org.uk/python/configobj.html
9
10
10 # Released subject to the BSD License
11 # Released subject to the BSD License
11 # Please see http://www.voidspace.org.uk/python/license.shtml
12 # Please see http://www.voidspace.org.uk/python/license.shtml
12
13
13 # Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
14 # Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
14 # For information about bugfixes, updates and support, please join the
15 # For information about bugfixes, updates and support, please join the
15 # ConfigObj mailing list:
16 # ConfigObj mailing list:
16 # http://lists.sourceforge.net/lists/listinfo/configobj-develop
17 # http://lists.sourceforge.net/lists/listinfo/configobj-develop
17 # Comments, suggestions and bug reports welcome.
18 # Comments, suggestions and bug reports welcome.
18
19
19 from __future__ import generators
20 from __future__ import generators
20
21
21 import sys
22 import sys
22 INTP_VER = sys.version_info[:2]
23 INTP_VER = sys.version_info[:2]
23 if INTP_VER < (2, 2):
24 if INTP_VER < (2, 2):
24 raise RuntimeError("Python v.2.2 or later needed")
25 raise RuntimeError("Python v.2.2 or later needed")
25
26
26 import os, re
27 import os, re
27 compiler = None
28 compiler = None
28 try:
29 try:
29 import compiler
30 import compiler
30 except ImportError:
31 except ImportError:
31 # for IronPython
32 # for IronPython
32 pass
33 pass
33 from types import StringTypes
34 from types import StringTypes
34 from warnings import warn
35 from warnings import warn
35 try:
36 from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
36 from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
37 except ImportError:
38 # Python 2.2 does not have these
39 # UTF-8
40 BOM_UTF8 = '\xef\xbb\xbf'
41 # UTF-16, little endian
42 BOM_UTF16_LE = '\xff\xfe'
43 # UTF-16, big endian
44 BOM_UTF16_BE = '\xfe\xff'
45 if sys.byteorder == 'little':
46 # UTF-16, native endianness
47 BOM_UTF16 = BOM_UTF16_LE
48 else:
49 # UTF-16, native endianness
50 BOM_UTF16 = BOM_UTF16_BE
51
37
52 # A dictionary mapping BOM to
38 # A dictionary mapping BOM to
53 # the encoding to decode with, and what to set the
39 # the encoding to decode with, and what to set the
54 # encoding attribute to.
40 # encoding attribute to.
55 BOMS = {
41 BOMS = {
56 BOM_UTF8: ('utf_8', None),
42 BOM_UTF8: ('utf_8', None),
57 BOM_UTF16_BE: ('utf16_be', 'utf_16'),
43 BOM_UTF16_BE: ('utf16_be', 'utf_16'),
58 BOM_UTF16_LE: ('utf16_le', 'utf_16'),
44 BOM_UTF16_LE: ('utf16_le', 'utf_16'),
59 BOM_UTF16: ('utf_16', 'utf_16'),
45 BOM_UTF16: ('utf_16', 'utf_16'),
60 }
46 }
61 # All legal variants of the BOM codecs.
47 # All legal variants of the BOM codecs.
62 # TODO: the list of aliases is not meant to be exhaustive, is there a
48 # TODO: the list of aliases is not meant to be exhaustive, is there a
63 # better way ?
49 # better way ?
64 BOM_LIST = {
50 BOM_LIST = {
65 'utf_16': 'utf_16',
51 'utf_16': 'utf_16',
66 'u16': 'utf_16',
52 'u16': 'utf_16',
67 'utf16': 'utf_16',
53 'utf16': 'utf_16',
68 'utf-16': 'utf_16',
54 'utf-16': 'utf_16',
69 'utf16_be': 'utf16_be',
55 'utf16_be': 'utf16_be',
70 'utf_16_be': 'utf16_be',
56 'utf_16_be': 'utf16_be',
71 'utf-16be': 'utf16_be',
57 'utf-16be': 'utf16_be',
72 'utf16_le': 'utf16_le',
58 'utf16_le': 'utf16_le',
73 'utf_16_le': 'utf16_le',
59 'utf_16_le': 'utf16_le',
74 'utf-16le': 'utf16_le',
60 'utf-16le': 'utf16_le',
75 'utf_8': 'utf_8',
61 'utf_8': 'utf_8',
76 'u8': 'utf_8',
62 'u8': 'utf_8',
77 'utf': 'utf_8',
63 'utf': 'utf_8',
78 'utf8': 'utf_8',
64 'utf8': 'utf_8',
79 'utf-8': 'utf_8',
65 'utf-8': 'utf_8',
80 }
66 }
81
67
82 # Map of encodings to the BOM to write.
68 # Map of encodings to the BOM to write.
83 BOM_SET = {
69 BOM_SET = {
84 'utf_8': BOM_UTF8,
70 'utf_8': BOM_UTF8,
85 'utf_16': BOM_UTF16,
71 'utf_16': BOM_UTF16,
86 'utf16_be': BOM_UTF16_BE,
72 'utf16_be': BOM_UTF16_BE,
87 'utf16_le': BOM_UTF16_LE,
73 'utf16_le': BOM_UTF16_LE,
88 None: BOM_UTF8
74 None: BOM_UTF8
89 }
75 }
90
76
91
77
92 def match_utf8(encoding):
78 def match_utf8(encoding):
93 return BOM_LIST.get(encoding.lower()) == 'utf_8'
79 return BOM_LIST.get(encoding.lower()) == 'utf_8'
94
80
95
81
96 # Quote strings used for writing values
82 # Quote strings used for writing values
97 squot = "'%s'"
83 squot = "'%s'"
98 dquot = '"%s"'
84 dquot = '"%s"'
99 noquot = "%s"
85 noquot = "%s"
100 wspace_plus = ' \r\t\n\v\t\'"'
86 wspace_plus = ' \r\t\n\v\t\'"'
101 tsquot = '"""%s"""'
87 tsquot = '"""%s"""'
102 tdquot = "'''%s'''"
88 tdquot = "'''%s'''"
103
89
104 try:
105 enumerate
106 except NameError:
107 def enumerate(obj):
108 """enumerate for Python 2.2."""
109 i = -1
110 for item in obj:
111 i += 1
112 yield i, item
113
114 try:
115 True, False
116 except NameError:
117 True, False = 1, 0
118
119
90
120 __version__ = '4.5.2'
91 __version__ = '4.5.2'
121
92
122 __revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
93 __revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
123
94
124 __docformat__ = "restructuredtext en"
95 __docformat__ = "restructuredtext en"
125
96
126 __all__ = (
97 __all__ = (
127 '__version__',
98 '__version__',
128 'DEFAULT_INDENT_TYPE',
99 'DEFAULT_INDENT_TYPE',
129 'DEFAULT_INTERPOLATION',
100 'DEFAULT_INTERPOLATION',
130 'ConfigObjError',
101 'ConfigObjError',
131 'NestingError',
102 'NestingError',
132 'ParseError',
103 'ParseError',
133 'DuplicateError',
104 'DuplicateError',
134 'ConfigspecError',
105 'ConfigspecError',
135 'ConfigObj',
106 'ConfigObj',
136 'SimpleVal',
107 'SimpleVal',
137 'InterpolationError',
108 'InterpolationError',
138 'InterpolationLoopError',
109 'InterpolationLoopError',
139 'MissingInterpolationOption',
110 'MissingInterpolationOption',
140 'RepeatSectionError',
111 'RepeatSectionError',
141 'ReloadError',
112 'ReloadError',
142 'UnreprError',
113 'UnreprError',
143 'UnknownType',
114 'UnknownType',
144 '__docformat__',
115 '__docformat__',
145 'flatten_errors',
116 'flatten_errors',
146 )
117 )
147
118
148 DEFAULT_INTERPOLATION = 'configparser'
119 DEFAULT_INTERPOLATION = 'configparser'
149 DEFAULT_INDENT_TYPE = ' '
120 DEFAULT_INDENT_TYPE = ' '
150 MAX_INTERPOL_DEPTH = 10
121 MAX_INTERPOL_DEPTH = 10
151
122
152 OPTION_DEFAULTS = {
123 OPTION_DEFAULTS = {
153 'interpolation': True,
124 'interpolation': True,
154 'raise_errors': False,
125 'raise_errors': False,
155 'list_values': True,
126 'list_values': True,
156 'create_empty': False,
127 'create_empty': False,
157 'file_error': False,
128 'file_error': False,
158 'configspec': None,
129 'configspec': None,
159 'stringify': True,
130 'stringify': True,
160 # option may be set to one of ('', ' ', '\t')
131 # option may be set to one of ('', ' ', '\t')
161 'indent_type': None,
132 'indent_type': None,
162 'encoding': None,
133 'encoding': None,
163 'default_encoding': None,
134 'default_encoding': None,
164 'unrepr': False,
135 'unrepr': False,
165 'write_empty_values': False,
136 'write_empty_values': False,
166 }
137 }
167
138
168
139
169
140
170 def getObj(s):
141 def getObj(s):
171 s = "a=" + s
142 s = "a=" + s
172 if compiler is None:
143 if compiler is None:
173 raise ImportError('compiler module not available')
144 raise ImportError('compiler module not available')
174 p = compiler.parse(s)
145 p = compiler.parse(s)
175 return p.getChildren()[1].getChildren()[0].getChildren()[1]
146 return p.getChildren()[1].getChildren()[0].getChildren()[1]
176
147
177
148
178 class UnknownType(Exception):
149 class UnknownType(Exception):
179 pass
150 pass
180
151
181
152
182 class Builder(object):
153 class Builder(object):
183
154
184 def build(self, o):
155 def build(self, o):
185 m = getattr(self, 'build_' + o.__class__.__name__, None)
156 m = getattr(self, 'build_' + o.__class__.__name__, None)
186 if m is None:
157 if m is None:
187 raise UnknownType(o.__class__.__name__)
158 raise UnknownType(o.__class__.__name__)
188 return m(o)
159 return m(o)
189
160
190 def build_List(self, o):
161 def build_List(self, o):
191 return map(self.build, o.getChildren())
162 return map(self.build, o.getChildren())
192
163
193 def build_Const(self, o):
164 def build_Const(self, o):
194 return o.value
165 return o.value
195
166
196 def build_Dict(self, o):
167 def build_Dict(self, o):
197 d = {}
168 d = {}
198 i = iter(map(self.build, o.getChildren()))
169 i = iter(map(self.build, o.getChildren()))
199 for el in i:
170 for el in i:
200 d[el] = i.next()
171 d[el] = i.next()
201 return d
172 return d
202
173
203 def build_Tuple(self, o):
174 def build_Tuple(self, o):
204 return tuple(self.build_List(o))
175 return tuple(self.build_List(o))
205
176
206 def build_Name(self, o):
177 def build_Name(self, o):
207 if o.name == 'None':
178 if o.name == 'None':
208 return None
179 return None
209 if o.name == 'True':
180 if o.name == 'True':
210 return True
181 return True
211 if o.name == 'False':
182 if o.name == 'False':
212 return False
183 return False
213
184
214 # An undefined Name
185 # An undefined Name
215 raise UnknownType('Undefined Name')
186 raise UnknownType('Undefined Name')
216
187
217 def build_Add(self, o):
188 def build_Add(self, o):
218 real, imag = map(self.build_Const, o.getChildren())
189 real, imag = map(self.build_Const, o.getChildren())
219 try:
190 try:
220 real = float(real)
191 real = float(real)
221 except TypeError:
192 except TypeError:
222 raise UnknownType('Add')
193 raise UnknownType('Add')
223 if not isinstance(imag, complex) or imag.real != 0.0:
194 if not isinstance(imag, complex) or imag.real != 0.0:
224 raise UnknownType('Add')
195 raise UnknownType('Add')
225 return real+imag
196 return real+imag
226
197
227 def build_Getattr(self, o):
198 def build_Getattr(self, o):
228 parent = self.build(o.expr)
199 parent = self.build(o.expr)
229 return getattr(parent, o.attrname)
200 return getattr(parent, o.attrname)
230
201
231 def build_UnarySub(self, o):
202 def build_UnarySub(self, o):
232 return -self.build_Const(o.getChildren()[0])
203 return -self.build_Const(o.getChildren()[0])
233
204
234 def build_UnaryAdd(self, o):
205 def build_UnaryAdd(self, o):
235 return self.build_Const(o.getChildren()[0])
206 return self.build_Const(o.getChildren()[0])
236
207
237
208
238 _builder = Builder()
209 _builder = Builder()
239
210
240
211
241 def unrepr(s):
212 def unrepr(s):
242 if not s:
213 if not s:
243 return s
214 return s
244 return _builder.build(getObj(s))
215 return _builder.build(getObj(s))
245
216
246
217
247
218
248 class ConfigObjError(SyntaxError):
219 class ConfigObjError(SyntaxError):
249 """
220 """
250 This is the base class for all errors that ConfigObj raises.
221 This is the base class for all errors that ConfigObj raises.
251 It is a subclass of SyntaxError.
222 It is a subclass of SyntaxError.
252 """
223 """
253 def __init__(self, message='', line_number=None, line=''):
224 def __init__(self, message='', line_number=None, line=''):
254 self.line = line
225 self.line = line
255 self.line_number = line_number
226 self.line_number = line_number
256 self.message = message
227 self.message = message
257 SyntaxError.__init__(self, message)
228 SyntaxError.__init__(self, message)
258
229
259
230
260 class NestingError(ConfigObjError):
231 class NestingError(ConfigObjError):
261 """
232 """
262 This error indicates a level of nesting that doesn't match.
233 This error indicates a level of nesting that doesn't match.
263 """
234 """
264
235
265
236
266 class ParseError(ConfigObjError):
237 class ParseError(ConfigObjError):
267 """
238 """
268 This error indicates that a line is badly written.
239 This error indicates that a line is badly written.
269 It is neither a valid ``key = value`` line,
240 It is neither a valid ``key = value`` line,
270 nor a valid section marker line.
241 nor a valid section marker line.
271 """
242 """
272
243
273
244
274 class ReloadError(IOError):
245 class ReloadError(IOError):
275 """
246 """
276 A 'reload' operation failed.
247 A 'reload' operation failed.
277 This exception is a subclass of ``IOError``.
248 This exception is a subclass of ``IOError``.
278 """
249 """
279 def __init__(self):
250 def __init__(self):
280 IOError.__init__(self, 'reload failed, filename is not set.')
251 IOError.__init__(self, 'reload failed, filename is not set.')
281
252
282
253
283 class DuplicateError(ConfigObjError):
254 class DuplicateError(ConfigObjError):
284 """
255 """
285 The keyword or section specified already exists.
256 The keyword or section specified already exists.
286 """
257 """
287
258
288
259
289 class ConfigspecError(ConfigObjError):
260 class ConfigspecError(ConfigObjError):
290 """
261 """
291 An error occured whilst parsing a configspec.
262 An error occured whilst parsing a configspec.
292 """
263 """
293
264
294
265
295 class InterpolationError(ConfigObjError):
266 class InterpolationError(ConfigObjError):
296 """Base class for the two interpolation errors."""
267 """Base class for the two interpolation errors."""
297
268
298
269
299 class InterpolationLoopError(InterpolationError):
270 class InterpolationLoopError(InterpolationError):
300 """Maximum interpolation depth exceeded in string interpolation."""
271 """Maximum interpolation depth exceeded in string interpolation."""
301
272
302 def __init__(self, option):
273 def __init__(self, option):
303 InterpolationError.__init__(
274 InterpolationError.__init__(
304 self,
275 self,
305 'interpolation loop detected in value "%s".' % option)
276 'interpolation loop detected in value "%s".' % option)
306
277
307
278
308 class RepeatSectionError(ConfigObjError):
279 class RepeatSectionError(ConfigObjError):
309 """
280 """
310 This error indicates additional sections in a section with a
281 This error indicates additional sections in a section with a
311 ``__many__`` (repeated) section.
282 ``__many__`` (repeated) section.
312 """
283 """
313
284
314
285
315 class MissingInterpolationOption(InterpolationError):
286 class MissingInterpolationOption(InterpolationError):
316 """A value specified for interpolation was missing."""
287 """A value specified for interpolation was missing."""
317
288
318 def __init__(self, option):
289 def __init__(self, option):
319 InterpolationError.__init__(
290 InterpolationError.__init__(
320 self,
291 self,
321 'missing option "%s" in interpolation.' % option)
292 'missing option "%s" in interpolation.' % option)
322
293
323
294
324 class UnreprError(ConfigObjError):
295 class UnreprError(ConfigObjError):
325 """An error parsing in unrepr mode."""
296 """An error parsing in unrepr mode."""
326
297
327
298
328
299
329 class InterpolationEngine(object):
300 class InterpolationEngine(object):
330 """
301 """
331 A helper class to help perform string interpolation.
302 A helper class to help perform string interpolation.
332
303
333 This class is an abstract base class; its descendants perform
304 This class is an abstract base class; its descendants perform
334 the actual work.
305 the actual work.
335 """
306 """
336
307
337 # compiled regexp to use in self.interpolate()
308 # compiled regexp to use in self.interpolate()
338 _KEYCRE = re.compile(r"%\(([^)]*)\)s")
309 _KEYCRE = re.compile(r"%\(([^)]*)\)s")
339
310
340 def __init__(self, section):
311 def __init__(self, section):
341 # the Section instance that "owns" this engine
312 # the Section instance that "owns" this engine
342 self.section = section
313 self.section = section
343
314
344
315
345 def interpolate(self, key, value):
316 def interpolate(self, key, value):
346 def recursive_interpolate(key, value, section, backtrail):
317 def recursive_interpolate(key, value, section, backtrail):
347 """The function that does the actual work.
318 """The function that does the actual work.
348
319
349 ``value``: the string we're trying to interpolate.
320 ``value``: the string we're trying to interpolate.
350 ``section``: the section in which that string was found
321 ``section``: the section in which that string was found
351 ``backtrail``: a dict to keep track of where we've been,
322 ``backtrail``: a dict to keep track of where we've been,
352 to detect and prevent infinite recursion loops
323 to detect and prevent infinite recursion loops
353
324
354 This is similar to a depth-first-search algorithm.
325 This is similar to a depth-first-search algorithm.
355 """
326 """
356 # Have we been here already?
327 # Have we been here already?
357 if backtrail.has_key((key, section.name)):
328 if backtrail.has_key((key, section.name)):
358 # Yes - infinite loop detected
329 # Yes - infinite loop detected
359 raise InterpolationLoopError(key)
330 raise InterpolationLoopError(key)
360 # Place a marker on our backtrail so we won't come back here again
331 # Place a marker on our backtrail so we won't come back here again
361 backtrail[(key, section.name)] = 1
332 backtrail[(key, section.name)] = 1
362
333
363 # Now start the actual work
334 # Now start the actual work
364 match = self._KEYCRE.search(value)
335 match = self._KEYCRE.search(value)
365 while match:
336 while match:
366 # The actual parsing of the match is implementation-dependent,
337 # The actual parsing of the match is implementation-dependent,
367 # so delegate to our helper function
338 # so delegate to our helper function
368 k, v, s = self._parse_match(match)
339 k, v, s = self._parse_match(match)
369 if k is None:
340 if k is None:
370 # That's the signal that no further interpolation is needed
341 # That's the signal that no further interpolation is needed
371 replacement = v
342 replacement = v
372 else:
343 else:
373 # Further interpolation may be needed to obtain final value
344 # Further interpolation may be needed to obtain final value
374 replacement = recursive_interpolate(k, v, s, backtrail)
345 replacement = recursive_interpolate(k, v, s, backtrail)
375 # Replace the matched string with its final value
346 # Replace the matched string with its final value
376 start, end = match.span()
347 start, end = match.span()
377 value = ''.join((value[:start], replacement, value[end:]))
348 value = ''.join((value[:start], replacement, value[end:]))
378 new_search_start = start + len(replacement)
349 new_search_start = start + len(replacement)
379 # Pick up the next interpolation key, if any, for next time
350 # Pick up the next interpolation key, if any, for next time
380 # through the while loop
351 # through the while loop
381 match = self._KEYCRE.search(value, new_search_start)
352 match = self._KEYCRE.search(value, new_search_start)
382
353
383 # Now safe to come back here again; remove marker from backtrail
354 # Now safe to come back here again; remove marker from backtrail
384 del backtrail[(key, section.name)]
355 del backtrail[(key, section.name)]
385
356
386 return value
357 return value
387
358
388 # Back in interpolate(), all we have to do is kick off the recursive
359 # Back in interpolate(), all we have to do is kick off the recursive
389 # function with appropriate starting values
360 # function with appropriate starting values
390 value = recursive_interpolate(key, value, self.section, {})
361 value = recursive_interpolate(key, value, self.section, {})
391 return value
362 return value
392
363
393
364
394 def _fetch(self, key):
365 def _fetch(self, key):
395 """Helper function to fetch values from owning section.
366 """Helper function to fetch values from owning section.
396
367
397 Returns a 2-tuple: the value, and the section where it was found.
368 Returns a 2-tuple: the value, and the section where it was found.
398 """
369 """
399 # switch off interpolation before we try and fetch anything !
370 # switch off interpolation before we try and fetch anything !
400 save_interp = self.section.main.interpolation
371 save_interp = self.section.main.interpolation
401 self.section.main.interpolation = False
372 self.section.main.interpolation = False
402
373
403 # Start at section that "owns" this InterpolationEngine
374 # Start at section that "owns" this InterpolationEngine
404 current_section = self.section
375 current_section = self.section
405 while True:
376 while True:
406 # try the current section first
377 # try the current section first
407 val = current_section.get(key)
378 val = current_section.get(key)
408 if val is not None:
379 if val is not None:
409 break
380 break
410 # try "DEFAULT" next
381 # try "DEFAULT" next
411 val = current_section.get('DEFAULT', {}).get(key)
382 val = current_section.get('DEFAULT', {}).get(key)
412 if val is not None:
383 if val is not None:
413 break
384 break
414 # move up to parent and try again
385 # move up to parent and try again
415 # top-level's parent is itself
386 # top-level's parent is itself
416 if current_section.parent is current_section:
387 if current_section.parent is current_section:
417 # reached top level, time to give up
388 # reached top level, time to give up
418 break
389 break
419 current_section = current_section.parent
390 current_section = current_section.parent
420
391
421 # restore interpolation to previous value before returning
392 # restore interpolation to previous value before returning
422 self.section.main.interpolation = save_interp
393 self.section.main.interpolation = save_interp
423 if val is None:
394 if val is None:
424 raise MissingInterpolationOption(key)
395 raise MissingInterpolationOption(key)
425 return val, current_section
396 return val, current_section
426
397
427
398
428 def _parse_match(self, match):
399 def _parse_match(self, match):
429 """Implementation-dependent helper function.
400 """Implementation-dependent helper function.
430
401
431 Will be passed a match object corresponding to the interpolation
402 Will be passed a match object corresponding to the interpolation
432 key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
403 key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
433 key in the appropriate config file section (using the ``_fetch()``
404 key in the appropriate config file section (using the ``_fetch()``
434 helper function) and return a 3-tuple: (key, value, section)
405 helper function) and return a 3-tuple: (key, value, section)
435
406
436 ``key`` is the name of the key we're looking for
407 ``key`` is the name of the key we're looking for
437 ``value`` is the value found for that key
408 ``value`` is the value found for that key
438 ``section`` is a reference to the section where it was found
409 ``section`` is a reference to the section where it was found
439
410
440 ``key`` and ``section`` should be None if no further
411 ``key`` and ``section`` should be None if no further
441 interpolation should be performed on the resulting value
412 interpolation should be performed on the resulting value
442 (e.g., if we interpolated "$$" and returned "$").
413 (e.g., if we interpolated "$$" and returned "$").
443 """
414 """
444 raise NotImplementedError()
415 raise NotImplementedError()
445
416
446
417
447
418
448 class ConfigParserInterpolation(InterpolationEngine):
419 class ConfigParserInterpolation(InterpolationEngine):
449 """Behaves like ConfigParser."""
420 """Behaves like ConfigParser."""
450 _KEYCRE = re.compile(r"%\(([^)]*)\)s")
421 _KEYCRE = re.compile(r"%\(([^)]*)\)s")
451
422
452 def _parse_match(self, match):
423 def _parse_match(self, match):
453 key = match.group(1)
424 key = match.group(1)
454 value, section = self._fetch(key)
425 value, section = self._fetch(key)
455 return key, value, section
426 return key, value, section
456
427
457
428
458
429
459 class TemplateInterpolation(InterpolationEngine):
430 class TemplateInterpolation(InterpolationEngine):
460 """Behaves like string.Template."""
431 """Behaves like string.Template."""
461 _delimiter = '$'
432 _delimiter = '$'
462 _KEYCRE = re.compile(r"""
433 _KEYCRE = re.compile(r"""
463 \$(?:
434 \$(?:
464 (?P<escaped>\$) | # Two $ signs
435 (?P<escaped>\$) | # Two $ signs
465 (?P<named>[_a-z][_a-z0-9]*) | # $name format
436 (?P<named>[_a-z][_a-z0-9]*) | # $name format
466 {(?P<braced>[^}]*)} # ${name} format
437 {(?P<braced>[^}]*)} # ${name} format
467 )
438 )
468 """, re.IGNORECASE | re.VERBOSE)
439 """, re.IGNORECASE | re.VERBOSE)
469
440
470 def _parse_match(self, match):
441 def _parse_match(self, match):
471 # Valid name (in or out of braces): fetch value from section
442 # Valid name (in or out of braces): fetch value from section
472 key = match.group('named') or match.group('braced')
443 key = match.group('named') or match.group('braced')
473 if key is not None:
444 if key is not None:
474 value, section = self._fetch(key)
445 value, section = self._fetch(key)
475 return key, value, section
446 return key, value, section
476 # Escaped delimiter (e.g., $$): return single delimiter
447 # Escaped delimiter (e.g., $$): return single delimiter
477 if match.group('escaped') is not None:
448 if match.group('escaped') is not None:
478 # Return None for key and section to indicate it's time to stop
449 # Return None for key and section to indicate it's time to stop
479 return None, self._delimiter, None
450 return None, self._delimiter, None
480 # Anything else: ignore completely, just return it unchanged
451 # Anything else: ignore completely, just return it unchanged
481 return None, match.group(), None
452 return None, match.group(), None
482
453
483
454
484 interpolation_engines = {
455 interpolation_engines = {
485 'configparser': ConfigParserInterpolation,
456 'configparser': ConfigParserInterpolation,
486 'template': TemplateInterpolation,
457 'template': TemplateInterpolation,
487 }
458 }
488
459
489
460
490
461
491 class Section(dict):
462 class Section(dict):
492 """
463 """
493 A dictionary-like object that represents a section in a config file.
464 A dictionary-like object that represents a section in a config file.
494
465
495 It does string interpolation if the 'interpolation' attribute
466 It does string interpolation if the 'interpolation' attribute
496 of the 'main' object is set to True.
467 of the 'main' object is set to True.
497
468
498 Interpolation is tried first from this object, then from the 'DEFAULT'
469 Interpolation is tried first from this object, then from the 'DEFAULT'
499 section of this object, next from the parent and its 'DEFAULT' section,
470 section of this object, next from the parent and its 'DEFAULT' section,
500 and so on until the main object is reached.
471 and so on until the main object is reached.
501
472
502 A Section will behave like an ordered dictionary - following the
473 A Section will behave like an ordered dictionary - following the
503 order of the ``scalars`` and ``sections`` attributes.
474 order of the ``scalars`` and ``sections`` attributes.
504 You can use this to change the order of members.
475 You can use this to change the order of members.
505
476
506 Iteration follows the order: scalars, then sections.
477 Iteration follows the order: scalars, then sections.
507 """
478 """
508
479
509 def __init__(self, parent, depth, main, indict=None, name=None):
480 def __init__(self, parent, depth, main, indict=None, name=None):
510 """
481 """
511 * parent is the section above
482 * parent is the section above
512 * depth is the depth level of this section
483 * depth is the depth level of this section
513 * main is the main ConfigObj
484 * main is the main ConfigObj
514 * indict is a dictionary to initialise the section with
485 * indict is a dictionary to initialise the section with
515 """
486 """
516 if indict is None:
487 if indict is None:
517 indict = {}
488 indict = {}
518 dict.__init__(self)
489 dict.__init__(self)
519 # used for nesting level *and* interpolation
490 # used for nesting level *and* interpolation
520 self.parent = parent
491 self.parent = parent
521 # used for the interpolation attribute
492 # used for the interpolation attribute
522 self.main = main
493 self.main = main
523 # level of nesting depth of this Section
494 # level of nesting depth of this Section
524 self.depth = depth
495 self.depth = depth
525 # purely for information
496 # purely for information
526 self.name = name
497 self.name = name
527 #
498 #
528 self._initialise()
499 self._initialise()
529 # we do this explicitly so that __setitem__ is used properly
500 # we do this explicitly so that __setitem__ is used properly
530 # (rather than just passing to ``dict.__init__``)
501 # (rather than just passing to ``dict.__init__``)
531 for entry, value in indict.iteritems():
502 for entry, value in indict.iteritems():
532 self[entry] = value
503 self[entry] = value
533
504
534
505
535 def _initialise(self):
506 def _initialise(self):
536 # the sequence of scalar values in this Section
507 # the sequence of scalar values in this Section
537 self.scalars = []
508 self.scalars = []
538 # the sequence of sections in this Section
509 # the sequence of sections in this Section
539 self.sections = []
510 self.sections = []
540 # for comments :-)
511 # for comments :-)
541 self.comments = {}
512 self.comments = {}
542 self.inline_comments = {}
513 self.inline_comments = {}
543 # for the configspec
514 # for the configspec
544 self.configspec = {}
515 self.configspec = {}
545 self._order = []
516 self._order = []
546 self._configspec_comments = {}
517 self._configspec_comments = {}
547 self._configspec_inline_comments = {}
518 self._configspec_inline_comments = {}
548 self._cs_section_comments = {}
519 self._cs_section_comments = {}
549 self._cs_section_inline_comments = {}
520 self._cs_section_inline_comments = {}
550 # for defaults
521 # for defaults
551 self.defaults = []
522 self.defaults = []
552 self.default_values = {}
523 self.default_values = {}
553
524
554
525
555 def _interpolate(self, key, value):
526 def _interpolate(self, key, value):
556 try:
527 try:
557 # do we already have an interpolation engine?
528 # do we already have an interpolation engine?
558 engine = self._interpolation_engine
529 engine = self._interpolation_engine
559 except AttributeError:
530 except AttributeError:
560 # not yet: first time running _interpolate(), so pick the engine
531 # not yet: first time running _interpolate(), so pick the engine
561 name = self.main.interpolation
532 name = self.main.interpolation
562 if name == True: # note that "if name:" would be incorrect here
533 if name == True: # note that "if name:" would be incorrect here
563 # backwards-compatibility: interpolation=True means use default
534 # backwards-compatibility: interpolation=True means use default
564 name = DEFAULT_INTERPOLATION
535 name = DEFAULT_INTERPOLATION
565 name = name.lower() # so that "Template", "template", etc. all work
536 name = name.lower() # so that "Template", "template", etc. all work
566 class_ = interpolation_engines.get(name, None)
537 class_ = interpolation_engines.get(name, None)
567 if class_ is None:
538 if class_ is None:
568 # invalid value for self.main.interpolation
539 # invalid value for self.main.interpolation
569 self.main.interpolation = False
540 self.main.interpolation = False
570 return value
541 return value
571 else:
542 else:
572 # save reference to engine so we don't have to do this again
543 # save reference to engine so we don't have to do this again
573 engine = self._interpolation_engine = class_(self)
544 engine = self._interpolation_engine = class_(self)
574 # let the engine do the actual work
545 # let the engine do the actual work
575 return engine.interpolate(key, value)
546 return engine.interpolate(key, value)
576
547
577
548
578 def __getitem__(self, key):
549 def __getitem__(self, key):
579 """Fetch the item and do string interpolation."""
550 """Fetch the item and do string interpolation."""
580 val = dict.__getitem__(self, key)
551 val = dict.__getitem__(self, key)
581 if self.main.interpolation and isinstance(val, StringTypes):
552 if self.main.interpolation and isinstance(val, StringTypes):
582 return self._interpolate(key, val)
553 return self._interpolate(key, val)
583 return val
554 return val
584
555
585
556
586 def __setitem__(self, key, value, unrepr=False):
557 def __setitem__(self, key, value, unrepr=False):
587 """
558 """
588 Correctly set a value.
559 Correctly set a value.
589
560
590 Making dictionary values Section instances.
561 Making dictionary values Section instances.
591 (We have to special case 'Section' instances - which are also dicts)
562 (We have to special case 'Section' instances - which are also dicts)
592
563
593 Keys must be strings.
564 Keys must be strings.
594 Values need only be strings (or lists of strings) if
565 Values need only be strings (or lists of strings) if
595 ``main.stringify`` is set.
566 ``main.stringify`` is set.
596
567
597 `unrepr`` must be set when setting a value to a dictionary, without
568 `unrepr`` must be set when setting a value to a dictionary, without
598 creating a new sub-section.
569 creating a new sub-section.
599 """
570 """
600 if not isinstance(key, StringTypes):
571 if not isinstance(key, StringTypes):
601 raise ValueError('The key "%s" is not a string.' % key)
572 raise ValueError('The key "%s" is not a string.' % key)
602
573
603 # add the comment
574 # add the comment
604 if not self.comments.has_key(key):
575 if not self.comments.has_key(key):
605 self.comments[key] = []
576 self.comments[key] = []
606 self.inline_comments[key] = ''
577 self.inline_comments[key] = ''
607 # remove the entry from defaults
578 # remove the entry from defaults
608 if key in self.defaults:
579 if key in self.defaults:
609 self.defaults.remove(key)
580 self.defaults.remove(key)
610 #
581 #
611 if isinstance(value, Section):
582 if isinstance(value, Section):
612 if not self.has_key(key):
583 if not self.has_key(key):
613 self.sections.append(key)
584 self.sections.append(key)
614 dict.__setitem__(self, key, value)
585 dict.__setitem__(self, key, value)
615 elif isinstance(value, dict) and not unrepr:
586 elif isinstance(value, dict) and not unrepr:
616 # First create the new depth level,
587 # First create the new depth level,
617 # then create the section
588 # then create the section
618 if not self.has_key(key):
589 if not self.has_key(key):
619 self.sections.append(key)
590 self.sections.append(key)
620 new_depth = self.depth + 1
591 new_depth = self.depth + 1
621 dict.__setitem__(
592 dict.__setitem__(
622 self,
593 self,
623 key,
594 key,
624 Section(
595 Section(
625 self,
596 self,
626 new_depth,
597 new_depth,
627 self.main,
598 self.main,
628 indict=value,
599 indict=value,
629 name=key))
600 name=key))
630 else:
601 else:
631 if not self.has_key(key):
602 if not self.has_key(key):
632 self.scalars.append(key)
603 self.scalars.append(key)
633 if not self.main.stringify:
604 if not self.main.stringify:
634 if isinstance(value, StringTypes):
605 if isinstance(value, StringTypes):
635 pass
606 pass
636 elif isinstance(value, (list, tuple)):
607 elif isinstance(value, (list, tuple)):
637 for entry in value:
608 for entry in value:
638 if not isinstance(entry, StringTypes):
609 if not isinstance(entry, StringTypes):
639 raise TypeError('Value is not a string "%s".' % entry)
610 raise TypeError('Value is not a string "%s".' % entry)
640 else:
611 else:
641 raise TypeError('Value is not a string "%s".' % value)
612 raise TypeError('Value is not a string "%s".' % value)
642 dict.__setitem__(self, key, value)
613 dict.__setitem__(self, key, value)
643
614
644
615
645 def __delitem__(self, key):
616 def __delitem__(self, key):
646 """Remove items from the sequence when deleting."""
617 """Remove items from the sequence when deleting."""
647 dict. __delitem__(self, key)
618 dict. __delitem__(self, key)
648 if key in self.scalars:
619 if key in self.scalars:
649 self.scalars.remove(key)
620 self.scalars.remove(key)
650 else:
621 else:
651 self.sections.remove(key)
622 self.sections.remove(key)
652 del self.comments[key]
623 del self.comments[key]
653 del self.inline_comments[key]
624 del self.inline_comments[key]
654
625
655
626
656 def get(self, key, default=None):
627 def get(self, key, default=None):
657 """A version of ``get`` that doesn't bypass string interpolation."""
628 """A version of ``get`` that doesn't bypass string interpolation."""
658 try:
629 try:
659 return self[key]
630 return self[key]
660 except KeyError:
631 except KeyError:
661 return default
632 return default
662
633
663
634
664 def update(self, indict):
635 def update(self, indict):
665 """
636 """
666 A version of update that uses our ``__setitem__``.
637 A version of update that uses our ``__setitem__``.
667 """
638 """
668 for entry in indict:
639 for entry in indict:
669 self[entry] = indict[entry]
640 self[entry] = indict[entry]
670
641
671
642
672 def pop(self, key, *args):
643 def pop(self, key, *args):
673 """
644 """
674 'D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
645 'D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
675 If key is not found, d is returned if given, otherwise KeyError is raised'
646 If key is not found, d is returned if given, otherwise KeyError is raised'
676 """
647 """
677 val = dict.pop(self, key, *args)
648 val = dict.pop(self, key, *args)
678 if key in self.scalars:
649 if key in self.scalars:
679 del self.comments[key]
650 del self.comments[key]
680 del self.inline_comments[key]
651 del self.inline_comments[key]
681 self.scalars.remove(key)
652 self.scalars.remove(key)
682 elif key in self.sections:
653 elif key in self.sections:
683 del self.comments[key]
654 del self.comments[key]
684 del self.inline_comments[key]
655 del self.inline_comments[key]
685 self.sections.remove(key)
656 self.sections.remove(key)
686 if self.main.interpolation and isinstance(val, StringTypes):
657 if self.main.interpolation and isinstance(val, StringTypes):
687 return self._interpolate(key, val)
658 return self._interpolate(key, val)
688 return val
659 return val
689
660
690
661
691 def popitem(self):
662 def popitem(self):
692 """Pops the first (key,val)"""
663 """Pops the first (key,val)"""
693 sequence = (self.scalars + self.sections)
664 sequence = (self.scalars + self.sections)
694 if not sequence:
665 if not sequence:
695 raise KeyError(": 'popitem(): dictionary is empty'")
666 raise KeyError(": 'popitem(): dictionary is empty'")
696 key = sequence[0]
667 key = sequence[0]
697 val = self[key]
668 val = self[key]
698 del self[key]
669 del self[key]
699 return key, val
670 return key, val
700
671
701
672
702 def clear(self):
673 def clear(self):
703 """
674 """
704 A version of clear that also affects scalars/sections
675 A version of clear that also affects scalars/sections
705 Also clears comments and configspec.
676 Also clears comments and configspec.
706
677
707 Leaves other attributes alone :
678 Leaves other attributes alone :
708 depth/main/parent are not affected
679 depth/main/parent are not affected
709 """
680 """
710 dict.clear(self)
681 dict.clear(self)
711 self.scalars = []
682 self.scalars = []
712 self.sections = []
683 self.sections = []
713 self.comments = {}
684 self.comments = {}
714 self.inline_comments = {}
685 self.inline_comments = {}
715 self.configspec = {}
686 self.configspec = {}
716
687
717
688
718 def setdefault(self, key, default=None):
689 def setdefault(self, key, default=None):
719 """A version of setdefault that sets sequence if appropriate."""
690 """A version of setdefault that sets sequence if appropriate."""
720 try:
691 try:
721 return self[key]
692 return self[key]
722 except KeyError:
693 except KeyError:
723 self[key] = default
694 self[key] = default
724 return self[key]
695 return self[key]
725
696
726
697
727 def items(self):
698 def items(self):
728 """D.items() -> list of D's (key, value) pairs, as 2-tuples"""
699 """D.items() -> list of D's (key, value) pairs, as 2-tuples"""
729 return zip((self.scalars + self.sections), self.values())
700 return zip((self.scalars + self.sections), self.values())
730
701
731
702
732 def keys(self):
703 def keys(self):
733 """D.keys() -> list of D's keys"""
704 """D.keys() -> list of D's keys"""
734 return (self.scalars + self.sections)
705 return (self.scalars + self.sections)
735
706
736
707
737 def values(self):
708 def values(self):
738 """D.values() -> list of D's values"""
709 """D.values() -> list of D's values"""
739 return [self[key] for key in (self.scalars + self.sections)]
710 return [self[key] for key in (self.scalars + self.sections)]
740
711
741
712
742 def iteritems(self):
713 def iteritems(self):
743 """D.iteritems() -> an iterator over the (key, value) items of D"""
714 """D.iteritems() -> an iterator over the (key, value) items of D"""
744 return iter(self.items())
715 return iter(self.items())
745
716
746
717
747 def iterkeys(self):
718 def iterkeys(self):
748 """D.iterkeys() -> an iterator over the keys of D"""
719 """D.iterkeys() -> an iterator over the keys of D"""
749 return iter((self.scalars + self.sections))
720 return iter((self.scalars + self.sections))
750
721
751 __iter__ = iterkeys
722 __iter__ = iterkeys
752
723
753
724
754 def itervalues(self):
725 def itervalues(self):
755 """D.itervalues() -> an iterator over the values of D"""
726 """D.itervalues() -> an iterator over the values of D"""
756 return iter(self.values())
727 return iter(self.values())
757
728
758
729
759 def __repr__(self):
730 def __repr__(self):
760 """x.__repr__() <==> repr(x)"""
731 """x.__repr__() <==> repr(x)"""
761 return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
732 return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
762 for key in (self.scalars + self.sections)])
733 for key in (self.scalars + self.sections)])
763
734
764 __str__ = __repr__
735 __str__ = __repr__
765 __str__.__doc__ = "x.__str__() <==> str(x)"
736 __str__.__doc__ = "x.__str__() <==> str(x)"
766
737
767
738
768 # Extra methods - not in a normal dictionary
739 # Extra methods - not in a normal dictionary
769
740
770 def dict(self):
741 def dict(self):
771 """
742 """
772 Return a deepcopy of self as a dictionary.
743 Return a deepcopy of self as a dictionary.
773
744
774 All members that are ``Section`` instances are recursively turned to
745 All members that are ``Section`` instances are recursively turned to
775 ordinary dictionaries - by calling their ``dict`` method.
746 ordinary dictionaries - by calling their ``dict`` method.
776
747
777 >>> n = a.dict()
748 >>> n = a.dict()
778 >>> n == a
749 >>> n == a
779 1
750 1
780 >>> n is a
751 >>> n is a
781 0
752 0
782 """
753 """
783 newdict = {}
754 newdict = {}
784 for entry in self:
755 for entry in self:
785 this_entry = self[entry]
756 this_entry = self[entry]
786 if isinstance(this_entry, Section):
757 if isinstance(this_entry, Section):
787 this_entry = this_entry.dict()
758 this_entry = this_entry.dict()
788 elif isinstance(this_entry, list):
759 elif isinstance(this_entry, list):
789 # create a copy rather than a reference
760 # create a copy rather than a reference
790 this_entry = list(this_entry)
761 this_entry = list(this_entry)
791 elif isinstance(this_entry, tuple):
762 elif isinstance(this_entry, tuple):
792 # create a copy rather than a reference
763 # create a copy rather than a reference
793 this_entry = tuple(this_entry)
764 this_entry = tuple(this_entry)
794 newdict[entry] = this_entry
765 newdict[entry] = this_entry
795 return newdict
766 return newdict
796
767
797
768
798 def merge(self, indict):
769 def merge(self, indict):
799 """
770 """
800 A recursive update - useful for merging config files.
771 A recursive update - useful for merging config files.
801
772
802 >>> a = '''[section1]
773 >>> a = '''[section1]
803 ... option1 = True
774 ... option1 = True
804 ... [[subsection]]
775 ... [[subsection]]
805 ... more_options = False
776 ... more_options = False
806 ... # end of file'''.splitlines()
777 ... # end of file'''.splitlines()
807 >>> b = '''# File is user.ini
778 >>> b = '''# File is user.ini
808 ... [section1]
779 ... [section1]
809 ... option1 = False
780 ... option1 = False
810 ... # end of file'''.splitlines()
781 ... # end of file'''.splitlines()
811 >>> c1 = ConfigObj(b)
782 >>> c1 = ConfigObj(b)
812 >>> c2 = ConfigObj(a)
783 >>> c2 = ConfigObj(a)
813 >>> c2.merge(c1)
784 >>> c2.merge(c1)
814 >>> c2
785 >>> c2
815 {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
786 {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
816 """
787 """
817 for key, val in indict.items():
788 for key, val in indict.iteritems():
818 if (key in self and isinstance(self[key], dict) and
789 if (key in self and isinstance(self[key], dict) and
819 isinstance(val, dict)):
790 isinstance(val, dict)):
820 self[key].merge(val)
791 self[key].merge(val)
821 else:
792 else:
822 self[key] = val
793 self[key] = val
823
794
824
795
825 def rename(self, oldkey, newkey):
796 def rename(self, oldkey, newkey):
826 """
797 """
827 Change a keyname to another, without changing position in sequence.
798 Change a keyname to another, without changing position in sequence.
828
799
829 Implemented so that transformations can be made on keys,
800 Implemented so that transformations can be made on keys,
830 as well as on values. (used by encode and decode)
801 as well as on values. (used by encode and decode)
831
802
832 Also renames comments.
803 Also renames comments.
833 """
804 """
834 if oldkey in self.scalars:
805 if oldkey in self.scalars:
835 the_list = self.scalars
806 the_list = self.scalars
836 elif oldkey in self.sections:
807 elif oldkey in self.sections:
837 the_list = self.sections
808 the_list = self.sections
838 else:
809 else:
839 raise KeyError('Key "%s" not found.' % oldkey)
810 raise KeyError('Key "%s" not found.' % oldkey)
840 pos = the_list.index(oldkey)
811 pos = the_list.index(oldkey)
841 #
812 #
842 val = self[oldkey]
813 val = self[oldkey]
843 dict.__delitem__(self, oldkey)
814 dict.__delitem__(self, oldkey)
844 dict.__setitem__(self, newkey, val)
815 dict.__setitem__(self, newkey, val)
845 the_list.remove(oldkey)
816 the_list.remove(oldkey)
846 the_list.insert(pos, newkey)
817 the_list.insert(pos, newkey)
847 comm = self.comments[oldkey]
818 comm = self.comments[oldkey]
848 inline_comment = self.inline_comments[oldkey]
819 inline_comment = self.inline_comments[oldkey]
849 del self.comments[oldkey]
820 del self.comments[oldkey]
850 del self.inline_comments[oldkey]
821 del self.inline_comments[oldkey]
851 self.comments[newkey] = comm
822 self.comments[newkey] = comm
852 self.inline_comments[newkey] = inline_comment
823 self.inline_comments[newkey] = inline_comment
853
824
854
825
855 def walk(self, function, raise_errors=True,
826 def walk(self, function, raise_errors=True,
856 call_on_sections=False, **keywargs):
827 call_on_sections=False, **keywargs):
857 """
828 """
858 Walk every member and call a function on the keyword and value.
829 Walk every member and call a function on the keyword and value.
859
830
860 Return a dictionary of the return values
831 Return a dictionary of the return values
861
832
862 If the function raises an exception, raise the errror
833 If the function raises an exception, raise the errror
863 unless ``raise_errors=False``, in which case set the return value to
834 unless ``raise_errors=False``, in which case set the return value to
864 ``False``.
835 ``False``.
865
836
866 Any unrecognised keyword arguments you pass to walk, will be pased on
837 Any unrecognised keyword arguments you pass to walk, will be pased on
867 to the function you pass in.
838 to the function you pass in.
868
839
869 Note: if ``call_on_sections`` is ``True`` then - on encountering a
840 Note: if ``call_on_sections`` is ``True`` then - on encountering a
870 subsection, *first* the function is called for the *whole* subsection,
841 subsection, *first* the function is called for the *whole* subsection,
871 and then recurses into it's members. This means your function must be
842 and then recurses into it's members. This means your function must be
872 able to handle strings, dictionaries and lists. This allows you
843 able to handle strings, dictionaries and lists. This allows you
873 to change the key of subsections as well as for ordinary members. The
844 to change the key of subsections as well as for ordinary members. The
874 return value when called on the whole subsection has to be discarded.
845 return value when called on the whole subsection has to be discarded.
875
846
876 See the encode and decode methods for examples, including functions.
847 See the encode and decode methods for examples, including functions.
877
848
878 .. caution::
849 .. caution::
879
850
880 You can use ``walk`` to transform the names of members of a section
851 You can use ``walk`` to transform the names of members of a section
881 but you mustn't add or delete members.
852 but you mustn't add or delete members.
882
853
883 >>> config = '''[XXXXsection]
854 >>> config = '''[XXXXsection]
884 ... XXXXkey = XXXXvalue'''.splitlines()
855 ... XXXXkey = XXXXvalue'''.splitlines()
885 >>> cfg = ConfigObj(config)
856 >>> cfg = ConfigObj(config)
886 >>> cfg
857 >>> cfg
887 {'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
858 {'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
888 >>> def transform(section, key):
859 >>> def transform(section, key):
889 ... val = section[key]
860 ... val = section[key]
890 ... newkey = key.replace('XXXX', 'CLIENT1')
861 ... newkey = key.replace('XXXX', 'CLIENT1')
891 ... section.rename(key, newkey)
862 ... section.rename(key, newkey)
892 ... if isinstance(val, (tuple, list, dict)):
863 ... if isinstance(val, (tuple, list, dict)):
893 ... pass
864 ... pass
894 ... else:
865 ... else:
895 ... val = val.replace('XXXX', 'CLIENT1')
866 ... val = val.replace('XXXX', 'CLIENT1')
896 ... section[newkey] = val
867 ... section[newkey] = val
897 >>> cfg.walk(transform, call_on_sections=True)
868 >>> cfg.walk(transform, call_on_sections=True)
898 {'CLIENT1section': {'CLIENT1key': None}}
869 {'CLIENT1section': {'CLIENT1key': None}}
899 >>> cfg
870 >>> cfg
900 {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}
871 {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}
901 """
872 """
902 out = {}
873 out = {}
903 # scalars first
874 # scalars first
904 for i in range(len(self.scalars)):
875 for i in range(len(self.scalars)):
905 entry = self.scalars[i]
876 entry = self.scalars[i]
906 try:
877 try:
907 val = function(self, entry, **keywargs)
878 val = function(self, entry, **keywargs)
908 # bound again in case name has changed
879 # bound again in case name has changed
909 entry = self.scalars[i]
880 entry = self.scalars[i]
910 out[entry] = val
881 out[entry] = val
911 except Exception:
882 except Exception:
912 if raise_errors:
883 if raise_errors:
913 raise
884 raise
914 else:
885 else:
915 entry = self.scalars[i]
886 entry = self.scalars[i]
916 out[entry] = False
887 out[entry] = False
917 # then sections
888 # then sections
918 for i in range(len(self.sections)):
889 for i in range(len(self.sections)):
919 entry = self.sections[i]
890 entry = self.sections[i]
920 if call_on_sections:
891 if call_on_sections:
921 try:
892 try:
922 function(self, entry, **keywargs)
893 function(self, entry, **keywargs)
923 except Exception:
894 except Exception:
924 if raise_errors:
895 if raise_errors:
925 raise
896 raise
926 else:
897 else:
927 entry = self.sections[i]
898 entry = self.sections[i]
928 out[entry] = False
899 out[entry] = False
929 # bound again in case name has changed
900 # bound again in case name has changed
930 entry = self.sections[i]
901 entry = self.sections[i]
931 # previous result is discarded
902 # previous result is discarded
932 out[entry] = self[entry].walk(
903 out[entry] = self[entry].walk(
933 function,
904 function,
934 raise_errors=raise_errors,
905 raise_errors=raise_errors,
935 call_on_sections=call_on_sections,
906 call_on_sections=call_on_sections,
936 **keywargs)
907 **keywargs)
937 return out
908 return out
938
909
939
910
940 def decode(self, encoding):
911 def decode(self, encoding):
941 """
912 """
942 Decode all strings and values to unicode, using the specified encoding.
913 Decode all strings and values to unicode, using the specified encoding.
943
914
944 Works with subsections and list values.
915 Works with subsections and list values.
945
916
946 Uses the ``walk`` method.
917 Uses the ``walk`` method.
947
918
948 Testing ``encode`` and ``decode``.
919 Testing ``encode`` and ``decode``.
949 >>> m = ConfigObj(a)
920 >>> m = ConfigObj(a)
950 >>> m.decode('ascii')
921 >>> m.decode('ascii')
951 >>> def testuni(val):
922 >>> def testuni(val):
952 ... for entry in val:
923 ... for entry in val:
953 ... if not isinstance(entry, unicode):
924 ... if not isinstance(entry, unicode):
954 ... print >> sys.stderr, type(entry)
925 ... print >> sys.stderr, type(entry)
955 ... raise AssertionError, 'decode failed.'
926 ... raise AssertionError, 'decode failed.'
956 ... if isinstance(val[entry], dict):
927 ... if isinstance(val[entry], dict):
957 ... testuni(val[entry])
928 ... testuni(val[entry])
958 ... elif not isinstance(val[entry], unicode):
929 ... elif not isinstance(val[entry], unicode):
959 ... raise AssertionError, 'decode failed.'
930 ... raise AssertionError, 'decode failed.'
960 >>> testuni(m)
931 >>> testuni(m)
961 >>> m.encode('ascii')
932 >>> m.encode('ascii')
962 >>> a == m
933 >>> a == m
963 1
934 1
964 """
935 """
965 warn('use of ``decode`` is deprecated.', DeprecationWarning)
936 warn('use of ``decode`` is deprecated.', DeprecationWarning)
966 def decode(section, key, encoding=encoding, warn=True):
937 def decode(section, key, encoding=encoding, warn=True):
967 """ """
938 """ """
968 val = section[key]
939 val = section[key]
969 if isinstance(val, (list, tuple)):
940 if isinstance(val, (list, tuple)):
970 newval = []
941 newval = []
971 for entry in val:
942 for entry in val:
972 newval.append(entry.decode(encoding))
943 newval.append(entry.decode(encoding))
973 elif isinstance(val, dict):
944 elif isinstance(val, dict):
974 newval = val
945 newval = val
975 else:
946 else:
976 newval = val.decode(encoding)
947 newval = val.decode(encoding)
977 newkey = key.decode(encoding)
948 newkey = key.decode(encoding)
978 section.rename(key, newkey)
949 section.rename(key, newkey)
979 section[newkey] = newval
950 section[newkey] = newval
980 # using ``call_on_sections`` allows us to modify section names
951 # using ``call_on_sections`` allows us to modify section names
981 self.walk(decode, call_on_sections=True)
952 self.walk(decode, call_on_sections=True)
982
953
983
954
984 def encode(self, encoding):
955 def encode(self, encoding):
985 """
956 """
986 Encode all strings and values from unicode,
957 Encode all strings and values from unicode,
987 using the specified encoding.
958 using the specified encoding.
988
959
989 Works with subsections and list values.
960 Works with subsections and list values.
990 Uses the ``walk`` method.
961 Uses the ``walk`` method.
991 """
962 """
992 warn('use of ``encode`` is deprecated.', DeprecationWarning)
963 warn('use of ``encode`` is deprecated.', DeprecationWarning)
993 def encode(section, key, encoding=encoding):
964 def encode(section, key, encoding=encoding):
994 """ """
965 """ """
995 val = section[key]
966 val = section[key]
996 if isinstance(val, (list, tuple)):
967 if isinstance(val, (list, tuple)):
997 newval = []
968 newval = []
998 for entry in val:
969 for entry in val:
999 newval.append(entry.encode(encoding))
970 newval.append(entry.encode(encoding))
1000 elif isinstance(val, dict):
971 elif isinstance(val, dict):
1001 newval = val
972 newval = val
1002 else:
973 else:
1003 newval = val.encode(encoding)
974 newval = val.encode(encoding)
1004 newkey = key.encode(encoding)
975 newkey = key.encode(encoding)
1005 section.rename(key, newkey)
976 section.rename(key, newkey)
1006 section[newkey] = newval
977 section[newkey] = newval
1007 self.walk(encode, call_on_sections=True)
978 self.walk(encode, call_on_sections=True)
1008
979
1009
980
1010 def istrue(self, key):
981 def istrue(self, key):
1011 """A deprecated version of ``as_bool``."""
982 """A deprecated version of ``as_bool``."""
1012 warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
983 warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
1013 'instead.', DeprecationWarning)
984 'instead.', DeprecationWarning)
1014 return self.as_bool(key)
985 return self.as_bool(key)
1015
986
1016
987
1017 def as_bool(self, key):
988 def as_bool(self, key):
1018 """
989 """
1019 Accepts a key as input. The corresponding value must be a string or
990 Accepts a key as input. The corresponding value must be a string or
1020 the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
991 the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
1021 retain compatibility with Python 2.2.
992 retain compatibility with Python 2.2.
1022
993
1023 If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
994 If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
1024 ``True``.
995 ``True``.
1025
996
1026 If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
997 If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
1027 ``False``.
998 ``False``.
1028
999
1029 ``as_bool`` is not case sensitive.
1000 ``as_bool`` is not case sensitive.
1030
1001
1031 Any other input will raise a ``ValueError``.
1002 Any other input will raise a ``ValueError``.
1032
1003
1033 >>> a = ConfigObj()
1004 >>> a = ConfigObj()
1034 >>> a['a'] = 'fish'
1005 >>> a['a'] = 'fish'
1035 >>> a.as_bool('a')
1006 >>> a.as_bool('a')
1036 Traceback (most recent call last):
1007 Traceback (most recent call last):
1037 ValueError: Value "fish" is neither True nor False
1008 ValueError: Value "fish" is neither True nor False
1038 >>> a['b'] = 'True'
1009 >>> a['b'] = 'True'
1039 >>> a.as_bool('b')
1010 >>> a.as_bool('b')
1040 1
1011 1
1041 >>> a['b'] = 'off'
1012 >>> a['b'] = 'off'
1042 >>> a.as_bool('b')
1013 >>> a.as_bool('b')
1043 0
1014 0
1044 """
1015 """
1045 val = self[key]
1016 val = self[key]
1046 if val == True:
1017 if val == True:
1047 return True
1018 return True
1048 elif val == False:
1019 elif val == False:
1049 return False
1020 return False
1050 else:
1021 else:
1051 try:
1022 try:
1052 if not isinstance(val, StringTypes):
1023 if not isinstance(val, StringTypes):
1053 # TODO: Why do we raise a KeyError here?
1024 # TODO: Why do we raise a KeyError here?
1054 raise KeyError()
1025 raise KeyError()
1055 else:
1026 else:
1056 return self.main._bools[val.lower()]
1027 return self.main._bools[val.lower()]
1057 except KeyError:
1028 except KeyError:
1058 raise ValueError('Value "%s" is neither True nor False' % val)
1029 raise ValueError('Value "%s" is neither True nor False' % val)
1059
1030
1060
1031
1061 def as_int(self, key):
1032 def as_int(self, key):
1062 """
1033 """
1063 A convenience method which coerces the specified value to an integer.
1034 A convenience method which coerces the specified value to an integer.
1064
1035
1065 If the value is an invalid literal for ``int``, a ``ValueError`` will
1036 If the value is an invalid literal for ``int``, a ``ValueError`` will
1066 be raised.
1037 be raised.
1067
1038
1068 >>> a = ConfigObj()
1039 >>> a = ConfigObj()
1069 >>> a['a'] = 'fish'
1040 >>> a['a'] = 'fish'
1070 >>> a.as_int('a')
1041 >>> a.as_int('a')
1071 Traceback (most recent call last):
1042 Traceback (most recent call last):
1072 ValueError: invalid literal for int(): fish
1043 ValueError: invalid literal for int(): fish
1073 >>> a['b'] = '1'
1044 >>> a['b'] = '1'
1074 >>> a.as_int('b')
1045 >>> a.as_int('b')
1075 1
1046 1
1076 >>> a['b'] = '3.2'
1047 >>> a['b'] = '3.2'
1077 >>> a.as_int('b')
1048 >>> a.as_int('b')
1078 Traceback (most recent call last):
1049 Traceback (most recent call last):
1079 ValueError: invalid literal for int(): 3.2
1050 ValueError: invalid literal for int(): 3.2
1080 """
1051 """
1081 return int(self[key])
1052 return int(self[key])
1082
1053
1083
1054
1084 def as_float(self, key):
1055 def as_float(self, key):
1085 """
1056 """
1086 A convenience method which coerces the specified value to a float.
1057 A convenience method which coerces the specified value to a float.
1087
1058
1088 If the value is an invalid literal for ``float``, a ``ValueError`` will
1059 If the value is an invalid literal for ``float``, a ``ValueError`` will
1089 be raised.
1060 be raised.
1090
1061
1091 >>> a = ConfigObj()
1062 >>> a = ConfigObj()
1092 >>> a['a'] = 'fish'
1063 >>> a['a'] = 'fish'
1093 >>> a.as_float('a')
1064 >>> a.as_float('a')
1094 Traceback (most recent call last):
1065 Traceback (most recent call last):
1095 ValueError: invalid literal for float(): fish
1066 ValueError: invalid literal for float(): fish
1096 >>> a['b'] = '1'
1067 >>> a['b'] = '1'
1097 >>> a.as_float('b')
1068 >>> a.as_float('b')
1098 1.0
1069 1.0
1099 >>> a['b'] = '3.2'
1070 >>> a['b'] = '3.2'
1100 >>> a.as_float('b')
1071 >>> a.as_float('b')
1101 3.2000000000000002
1072 3.2000000000000002
1102 """
1073 """
1103 return float(self[key])
1074 return float(self[key])
1104
1075
1105
1076
1106 def restore_default(self, key):
1077 def restore_default(self, key):
1107 """
1078 """
1108 Restore (and return) default value for the specified key.
1079 Restore (and return) default value for the specified key.
1109
1080
1110 This method will only work for a ConfigObj that was created
1081 This method will only work for a ConfigObj that was created
1111 with a configspec and has been validated.
1082 with a configspec and has been validated.
1112
1083
1113 If there is no default value for this key, ``KeyError`` is raised.
1084 If there is no default value for this key, ``KeyError`` is raised.
1114 """
1085 """
1115 default = self.default_values[key]
1086 default = self.default_values[key]
1116 dict.__setitem__(self, key, default)
1087 dict.__setitem__(self, key, default)
1117 if key not in self.defaults:
1088 if key not in self.defaults:
1118 self.defaults.append(key)
1089 self.defaults.append(key)
1119 return default
1090 return default
1120
1091
1121
1092
1122 def restore_defaults(self):
1093 def restore_defaults(self):
1123 """
1094 """
1124 Recursively restore default values to all members
1095 Recursively restore default values to all members
1125 that have them.
1096 that have them.
1126
1097
1127 This method will only work for a ConfigObj that was created
1098 This method will only work for a ConfigObj that was created
1128 with a configspec and has been validated.
1099 with a configspec and has been validated.
1129
1100
1130 It doesn't delete or modify entries without default values.
1101 It doesn't delete or modify entries without default values.
1131 """
1102 """
1132 for key in self.default_values:
1103 for key in self.default_values:
1133 self.restore_default(key)
1104 self.restore_default(key)
1134
1105
1135 for section in self.sections:
1106 for section in self.sections:
1136 self[section].restore_defaults()
1107 self[section].restore_defaults()
1137
1108
1138
1109
1139 class ConfigObj(Section):
1110 class ConfigObj(Section):
1140 """An object to read, create, and write config files."""
1111 """An object to read, create, and write config files."""
1141
1112
1142 _keyword = re.compile(r'''^ # line start
1113 _keyword = re.compile(r'''^ # line start
1143 (\s*) # indentation
1114 (\s*) # indentation
1144 ( # keyword
1115 ( # keyword
1145 (?:".*?")| # double quotes
1116 (?:".*?")| # double quotes
1146 (?:'.*?')| # single quotes
1117 (?:'.*?')| # single quotes
1147 (?:[^'"=].*?) # no quotes
1118 (?:[^'"=].*?) # no quotes
1148 )
1119 )
1149 \s*=\s* # divider
1120 \s*=\s* # divider
1150 (.*) # value (including list values and comments)
1121 (.*) # value (including list values and comments)
1151 $ # line end
1122 $ # line end
1152 ''',
1123 ''',
1153 re.VERBOSE)
1124 re.VERBOSE)
1154
1125
1155 _sectionmarker = re.compile(r'''^
1126 _sectionmarker = re.compile(r'''^
1156 (\s*) # 1: indentation
1127 (\s*) # 1: indentation
1157 ((?:\[\s*)+) # 2: section marker open
1128 ((?:\[\s*)+) # 2: section marker open
1158 ( # 3: section name open
1129 ( # 3: section name open
1159 (?:"\s*\S.*?\s*")| # at least one non-space with double quotes
1130 (?:"\s*\S.*?\s*")| # at least one non-space with double quotes
1160 (?:'\s*\S.*?\s*')| # at least one non-space with single quotes
1131 (?:'\s*\S.*?\s*')| # at least one non-space with single quotes
1161 (?:[^'"\s].*?) # at least one non-space unquoted
1132 (?:[^'"\s].*?) # at least one non-space unquoted
1162 ) # section name close
1133 ) # section name close
1163 ((?:\s*\])+) # 4: section marker close
1134 ((?:\s*\])+) # 4: section marker close
1164 \s*(\#.*)? # 5: optional comment
1135 \s*(\#.*)? # 5: optional comment
1165 $''',
1136 $''',
1166 re.VERBOSE)
1137 re.VERBOSE)
1167
1138
1168 # this regexp pulls list values out as a single string
1139 # this regexp pulls list values out as a single string
1169 # or single values and comments
1140 # or single values and comments
1170 # FIXME: this regex adds a '' to the end of comma terminated lists
1141 # FIXME: this regex adds a '' to the end of comma terminated lists
1171 # workaround in ``_handle_value``
1142 # workaround in ``_handle_value``
1172 _valueexp = re.compile(r'''^
1143 _valueexp = re.compile(r'''^
1173 (?:
1144 (?:
1174 (?:
1145 (?:
1175 (
1146 (
1176 (?:
1147 (?:
1177 (?:
1148 (?:
1178 (?:".*?")| # double quotes
1149 (?:".*?")| # double quotes
1179 (?:'.*?')| # single quotes
1150 (?:'.*?')| # single quotes
1180 (?:[^'",\#][^,\#]*?) # unquoted
1151 (?:[^'",\#][^,\#]*?) # unquoted
1181 )
1152 )
1182 \s*,\s* # comma
1153 \s*,\s* # comma
1183 )* # match all list items ending in a comma (if any)
1154 )* # match all list items ending in a comma (if any)
1184 )
1155 )
1185 (
1156 (
1186 (?:".*?")| # double quotes
1157 (?:".*?")| # double quotes
1187 (?:'.*?')| # single quotes
1158 (?:'.*?')| # single quotes
1188 (?:[^'",\#\s][^,]*?)| # unquoted
1159 (?:[^'",\#\s][^,]*?)| # unquoted
1189 (?:(?<!,)) # Empty value
1160 (?:(?<!,)) # Empty value
1190 )? # last item in a list - or string value
1161 )? # last item in a list - or string value
1191 )|
1162 )|
1192 (,) # alternatively a single comma - empty list
1163 (,) # alternatively a single comma - empty list
1193 )
1164 )
1194 \s*(\#.*)? # optional comment
1165 \s*(\#.*)? # optional comment
1195 $''',
1166 $''',
1196 re.VERBOSE)
1167 re.VERBOSE)
1197
1168
1198 # use findall to get the members of a list value
1169 # use findall to get the members of a list value
1199 _listvalueexp = re.compile(r'''
1170 _listvalueexp = re.compile(r'''
1200 (
1171 (
1201 (?:".*?")| # double quotes
1172 (?:".*?")| # double quotes
1202 (?:'.*?')| # single quotes
1173 (?:'.*?')| # single quotes
1203 (?:[^'",\#].*?) # unquoted
1174 (?:[^'",\#].*?) # unquoted
1204 )
1175 )
1205 \s*,\s* # comma
1176 \s*,\s* # comma
1206 ''',
1177 ''',
1207 re.VERBOSE)
1178 re.VERBOSE)
1208
1179
1209 # this regexp is used for the value
1180 # this regexp is used for the value
1210 # when lists are switched off
1181 # when lists are switched off
1211 _nolistvalue = re.compile(r'''^
1182 _nolistvalue = re.compile(r'''^
1212 (
1183 (
1213 (?:".*?")| # double quotes
1184 (?:".*?")| # double quotes
1214 (?:'.*?')| # single quotes
1185 (?:'.*?')| # single quotes
1215 (?:[^'"\#].*?)| # unquoted
1186 (?:[^'"\#].*?)| # unquoted
1216 (?:) # Empty value
1187 (?:) # Empty value
1217 )
1188 )
1218 \s*(\#.*)? # optional comment
1189 \s*(\#.*)? # optional comment
1219 $''',
1190 $''',
1220 re.VERBOSE)
1191 re.VERBOSE)
1221
1192
1222 # regexes for finding triple quoted values on one line
1193 # regexes for finding triple quoted values on one line
1223 _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
1194 _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
1224 _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
1195 _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
1225 _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
1196 _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
1226 _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
1197 _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
1227
1198
1228 _triple_quote = {
1199 _triple_quote = {
1229 "'''": (_single_line_single, _multi_line_single),
1200 "'''": (_single_line_single, _multi_line_single),
1230 '"""': (_single_line_double, _multi_line_double),
1201 '"""': (_single_line_double, _multi_line_double),
1231 }
1202 }
1232
1203
1233 # Used by the ``istrue`` Section method
1204 # Used by the ``istrue`` Section method
1234 _bools = {
1205 _bools = {
1235 'yes': True, 'no': False,
1206 'yes': True, 'no': False,
1236 'on': True, 'off': False,
1207 'on': True, 'off': False,
1237 '1': True, '0': False,
1208 '1': True, '0': False,
1238 'true': True, 'false': False,
1209 'true': True, 'false': False,
1239 }
1210 }
1240
1211
1241
1212
1242 def __init__(self, infile=None, options=None, **kwargs):
1213 def __init__(self, infile=None, options=None, **kwargs):
1243 """
1214 """
1244 Parse a config file or create a config file object.
1215 Parse a config file or create a config file object.
1245
1216
1246 ``ConfigObj(infile=None, options=None, **kwargs)``
1217 ``ConfigObj(infile=None, options=None, **kwargs)``
1247 """
1218 """
1248 # init the superclass
1219 # init the superclass
1249 Section.__init__(self, self, 0, self)
1220 Section.__init__(self, self, 0, self)
1250
1221
1251 if infile is None:
1222 if infile is None:
1252 infile = []
1223 infile = []
1253 if options is None:
1224 if options is None:
1254 options = {}
1225 options = {}
1255 else:
1226 else:
1256 options = dict(options)
1227 options = dict(options)
1257
1228
1258 # keyword arguments take precedence over an options dictionary
1229 # keyword arguments take precedence over an options dictionary
1259 options.update(kwargs)
1230 options.update(kwargs)
1260
1231
1261 defaults = OPTION_DEFAULTS.copy()
1232 defaults = OPTION_DEFAULTS.copy()
1262 # TODO: check the values too.
1233 # TODO: check the values too.
1263 for entry in options:
1234 for entry in options:
1264 if entry not in defaults:
1235 if entry not in defaults:
1265 raise TypeError('Unrecognised option "%s".' % entry)
1236 raise TypeError('Unrecognised option "%s".' % entry)
1266
1237
1267 # Add any explicit options to the defaults
1238 # Add any explicit options to the defaults
1268 defaults.update(options)
1239 defaults.update(options)
1269 self._initialise(defaults)
1240 self._initialise(defaults)
1270 configspec = defaults['configspec']
1241 configspec = defaults['configspec']
1271 self._original_configspec = configspec
1242 self._original_configspec = configspec
1272 self._load(infile, configspec)
1243 self._load(infile, configspec)
1273
1244
1274
1245
1275 def _load(self, infile, configspec):
1246 def _load(self, infile, configspec):
1276 if isinstance(infile, StringTypes):
1247 if isinstance(infile, StringTypes):
1277 self.filename = infile
1248 self.filename = infile
1278 if os.path.isfile(infile):
1249 if os.path.isfile(infile):
1279 h = open(infile, 'rb')
1250 h = open(infile, 'rb')
1280 infile = h.read() or []
1251 infile = h.read() or []
1281 h.close()
1252 h.close()
1282 elif self.file_error:
1253 elif self.file_error:
1283 # raise an error if the file doesn't exist
1254 # raise an error if the file doesn't exist
1284 raise IOError('Config file not found: "%s".' % self.filename)
1255 raise IOError('Config file not found: "%s".' % self.filename)
1285 else:
1256 else:
1286 # file doesn't already exist
1257 # file doesn't already exist
1287 if self.create_empty:
1258 if self.create_empty:
1288 # this is a good test that the filename specified
1259 # this is a good test that the filename specified
1289 # isn't impossible - like on a non-existent device
1260 # isn't impossible - like on a non-existent device
1290 h = open(infile, 'w')
1261 h = open(infile, 'w')
1291 h.write('')
1262 h.write('')
1292 h.close()
1263 h.close()
1293 infile = []
1264 infile = []
1294
1265
1295 elif isinstance(infile, (list, tuple)):
1266 elif isinstance(infile, (list, tuple)):
1296 infile = list(infile)
1267 infile = list(infile)
1297
1268
1298 elif isinstance(infile, dict):
1269 elif isinstance(infile, dict):
1299 # initialise self
1270 # initialise self
1300 # the Section class handles creating subsections
1271 # the Section class handles creating subsections
1301 if isinstance(infile, ConfigObj):
1272 if isinstance(infile, ConfigObj):
1302 # get a copy of our ConfigObj
1273 # get a copy of our ConfigObj
1303 infile = infile.dict()
1274 infile = infile.dict()
1304
1275
1305 for entry in infile:
1276 for entry in infile:
1306 self[entry] = infile[entry]
1277 self[entry] = infile[entry]
1307 del self._errors
1278 del self._errors
1308
1279
1309 if configspec is not None:
1280 if configspec is not None:
1310 self._handle_configspec(configspec)
1281 self._handle_configspec(configspec)
1311 else:
1282 else:
1312 self.configspec = None
1283 self.configspec = None
1313 return
1284 return
1314
1285
1315 elif hasattr(infile, 'read'):
1286 elif hasattr(infile, 'read'):
1316 # This supports file like objects
1287 # This supports file like objects
1317 infile = infile.read() or []
1288 infile = infile.read() or []
1318 # needs splitting into lines - but needs doing *after* decoding
1289 # needs splitting into lines - but needs doing *after* decoding
1319 # in case it's not an 8 bit encoding
1290 # in case it's not an 8 bit encoding
1320 else:
1291 else:
1321 raise TypeError('infile must be a filename, file like object, or list of lines.')
1292 raise TypeError('infile must be a filename, file like object, or list of lines.')
1322
1293
1323 if infile:
1294 if infile:
1324 # don't do it for the empty ConfigObj
1295 # don't do it for the empty ConfigObj
1325 infile = self._handle_bom(infile)
1296 infile = self._handle_bom(infile)
1326 # infile is now *always* a list
1297 # infile is now *always* a list
1327 #
1298 #
1328 # Set the newlines attribute (first line ending it finds)
1299 # Set the newlines attribute (first line ending it finds)
1329 # and strip trailing '\n' or '\r' from lines
1300 # and strip trailing '\n' or '\r' from lines
1330 for line in infile:
1301 for line in infile:
1331 if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
1302 if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
1332 continue
1303 continue
1333 for end in ('\r\n', '\n', '\r'):
1304 for end in ('\r\n', '\n', '\r'):
1334 if line.endswith(end):
1305 if line.endswith(end):
1335 self.newlines = end
1306 self.newlines = end
1336 break
1307 break
1337 break
1308 break
1338
1309
1339 infile = [line.rstrip('\r\n') for line in infile]
1310 infile = [line.rstrip('\r\n') for line in infile]
1340
1311
1341 self._parse(infile)
1312 self._parse(infile)
1342 # if we had any errors, now is the time to raise them
1313 # if we had any errors, now is the time to raise them
1343 if self._errors:
1314 if self._errors:
1344 info = "at line %s." % self._errors[0].line_number
1315 info = "at line %s." % self._errors[0].line_number
1345 if len(self._errors) > 1:
1316 if len(self._errors) > 1:
1346 msg = "Parsing failed with several errors.\nFirst error %s" % info
1317 msg = "Parsing failed with several errors.\nFirst error %s" % info
1347 error = ConfigObjError(msg)
1318 error = ConfigObjError(msg)
1348 else:
1319 else:
1349 error = self._errors[0]
1320 error = self._errors[0]
1350 # set the errors attribute; it's a list of tuples:
1321 # set the errors attribute; it's a list of tuples:
1351 # (error_type, message, line_number)
1322 # (error_type, message, line_number)
1352 error.errors = self._errors
1323 error.errors = self._errors
1353 # set the config attribute
1324 # set the config attribute
1354 error.config = self
1325 error.config = self
1355 raise error
1326 raise error
1356 # delete private attributes
1327 # delete private attributes
1357 del self._errors
1328 del self._errors
1358
1329
1359 if configspec is None:
1330 if configspec is None:
1360 self.configspec = None
1331 self.configspec = None
1361 else:
1332 else:
1362 self._handle_configspec(configspec)
1333 self._handle_configspec(configspec)
1363
1334
1364
1335
1365 def _initialise(self, options=None):
1336 def _initialise(self, options=None):
1366 if options is None:
1337 if options is None:
1367 options = OPTION_DEFAULTS
1338 options = OPTION_DEFAULTS
1368
1339
1369 # initialise a few variables
1340 # initialise a few variables
1370 self.filename = None
1341 self.filename = None
1371 self._errors = []
1342 self._errors = []
1372 self.raise_errors = options['raise_errors']
1343 self.raise_errors = options['raise_errors']
1373 self.interpolation = options['interpolation']
1344 self.interpolation = options['interpolation']
1374 self.list_values = options['list_values']
1345 self.list_values = options['list_values']
1375 self.create_empty = options['create_empty']
1346 self.create_empty = options['create_empty']
1376 self.file_error = options['file_error']
1347 self.file_error = options['file_error']
1377 self.stringify = options['stringify']
1348 self.stringify = options['stringify']
1378 self.indent_type = options['indent_type']
1349 self.indent_type = options['indent_type']
1379 self.encoding = options['encoding']
1350 self.encoding = options['encoding']
1380 self.default_encoding = options['default_encoding']
1351 self.default_encoding = options['default_encoding']
1381 self.BOM = False
1352 self.BOM = False
1382 self.newlines = None
1353 self.newlines = None
1383 self.write_empty_values = options['write_empty_values']
1354 self.write_empty_values = options['write_empty_values']
1384 self.unrepr = options['unrepr']
1355 self.unrepr = options['unrepr']
1385
1356
1386 self.initial_comment = []
1357 self.initial_comment = []
1387 self.final_comment = []
1358 self.final_comment = []
1388 self.configspec = {}
1359 self.configspec = {}
1389
1360
1390 # Clear section attributes as well
1361 # Clear section attributes as well
1391 Section._initialise(self)
1362 Section._initialise(self)
1392
1363
1393
1364
1394 def __repr__(self):
1365 def __repr__(self):
1395 return ('ConfigObj({%s})' %
1366 return ('ConfigObj({%s})' %
1396 ', '.join([('%s: %s' % (repr(key), repr(self[key])))
1367 ', '.join([('%s: %s' % (repr(key), repr(self[key])))
1397 for key in (self.scalars + self.sections)]))
1368 for key in (self.scalars + self.sections)]))
1398
1369
1399
1370
1400 def _handle_bom(self, infile):
1371 def _handle_bom(self, infile):
1401 """
1372 """
1402 Handle any BOM, and decode if necessary.
1373 Handle any BOM, and decode if necessary.
1403
1374
1404 If an encoding is specified, that *must* be used - but the BOM should
1375 If an encoding is specified, that *must* be used - but the BOM should
1405 still be removed (and the BOM attribute set).
1376 still be removed (and the BOM attribute set).
1406
1377
1407 (If the encoding is wrongly specified, then a BOM for an alternative
1378 (If the encoding is wrongly specified, then a BOM for an alternative
1408 encoding won't be discovered or removed.)
1379 encoding won't be discovered or removed.)
1409
1380
1410 If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
1381 If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
1411 removed. The BOM attribute will be set. UTF16 will be decoded to
1382 removed. The BOM attribute will be set. UTF16 will be decoded to
1412 unicode.
1383 unicode.
1413
1384
1414 NOTE: This method must not be called with an empty ``infile``.
1385 NOTE: This method must not be called with an empty ``infile``.
1415
1386
1416 Specifying the *wrong* encoding is likely to cause a
1387 Specifying the *wrong* encoding is likely to cause a
1417 ``UnicodeDecodeError``.
1388 ``UnicodeDecodeError``.
1418
1389
1419 ``infile`` must always be returned as a list of lines, but may be
1390 ``infile`` must always be returned as a list of lines, but may be
1420 passed in as a single string.
1391 passed in as a single string.
1421 """
1392 """
1422 if ((self.encoding is not None) and
1393 if ((self.encoding is not None) and
1423 (self.encoding.lower() not in BOM_LIST)):
1394 (self.encoding.lower() not in BOM_LIST)):
1424 # No need to check for a BOM
1395 # No need to check for a BOM
1425 # the encoding specified doesn't have one
1396 # the encoding specified doesn't have one
1426 # just decode
1397 # just decode
1427 return self._decode(infile, self.encoding)
1398 return self._decode(infile, self.encoding)
1428
1399
1429 if isinstance(infile, (list, tuple)):
1400 if isinstance(infile, (list, tuple)):
1430 line = infile[0]
1401 line = infile[0]
1431 else:
1402 else:
1432 line = infile
1403 line = infile
1433 if self.encoding is not None:
1404 if self.encoding is not None:
1434 # encoding explicitly supplied
1405 # encoding explicitly supplied
1435 # And it could have an associated BOM
1406 # And it could have an associated BOM
1436 # TODO: if encoding is just UTF16 - we ought to check for both
1407 # TODO: if encoding is just UTF16 - we ought to check for both
1437 # TODO: big endian and little endian versions.
1408 # TODO: big endian and little endian versions.
1438 enc = BOM_LIST[self.encoding.lower()]
1409 enc = BOM_LIST[self.encoding.lower()]
1439 if enc == 'utf_16':
1410 if enc == 'utf_16':
1440 # For UTF16 we try big endian and little endian
1411 # For UTF16 we try big endian and little endian
1441 for BOM, (encoding, final_encoding) in BOMS.items():
1412 for BOM, (encoding, final_encoding) in BOMS.iteritems():
1442 if not final_encoding:
1413 if not final_encoding:
1443 # skip UTF8
1414 # skip UTF8
1444 continue
1415 continue
1445 if infile.startswith(BOM):
1416 if infile.startswith(BOM):
1446 ### BOM discovered
1417 ### BOM discovered
1447 ##self.BOM = True
1418 ##self.BOM = True
1448 # Don't need to remove BOM
1419 # Don't need to remove BOM
1449 return self._decode(infile, encoding)
1420 return self._decode(infile, encoding)
1450
1421
1451 # If we get this far, will *probably* raise a DecodeError
1422 # If we get this far, will *probably* raise a DecodeError
1452 # As it doesn't appear to start with a BOM
1423 # As it doesn't appear to start with a BOM
1453 return self._decode(infile, self.encoding)
1424 return self._decode(infile, self.encoding)
1454
1425
1455 # Must be UTF8
1426 # Must be UTF8
1456 BOM = BOM_SET[enc]
1427 BOM = BOM_SET[enc]
1457 if not line.startswith(BOM):
1428 if not line.startswith(BOM):
1458 return self._decode(infile, self.encoding)
1429 return self._decode(infile, self.encoding)
1459
1430
1460 newline = line[len(BOM):]
1431 newline = line[len(BOM):]
1461
1432
1462 # BOM removed
1433 # BOM removed
1463 if isinstance(infile, (list, tuple)):
1434 if isinstance(infile, (list, tuple)):
1464 infile[0] = newline
1435 infile[0] = newline
1465 else:
1436 else:
1466 infile = newline
1437 infile = newline
1467 self.BOM = True
1438 self.BOM = True
1468 return self._decode(infile, self.encoding)
1439 return self._decode(infile, self.encoding)
1469
1440
1470 # No encoding specified - so we need to check for UTF8/UTF16
1441 # No encoding specified - so we need to check for UTF8/UTF16
1471 for BOM, (encoding, final_encoding) in BOMS.items():
1442 for BOM, (encoding, final_encoding) in BOMS.iteritems():
1472 if not line.startswith(BOM):
1443 if not line.startswith(BOM):
1473 continue
1444 continue
1474 else:
1445 else:
1475 # BOM discovered
1446 # BOM discovered
1476 self.encoding = final_encoding
1447 self.encoding = final_encoding
1477 if not final_encoding:
1448 if not final_encoding:
1478 self.BOM = True
1449 self.BOM = True
1479 # UTF8
1450 # UTF8
1480 # remove BOM
1451 # remove BOM
1481 newline = line[len(BOM):]
1452 newline = line[len(BOM):]
1482 if isinstance(infile, (list, tuple)):
1453 if isinstance(infile, (list, tuple)):
1483 infile[0] = newline
1454 infile[0] = newline
1484 else:
1455 else:
1485 infile = newline
1456 infile = newline
1486 # UTF8 - don't decode
1457 # UTF8 - don't decode
1487 if isinstance(infile, StringTypes):
1458 if isinstance(infile, StringTypes):
1488 return infile.splitlines(True)
1459 return infile.splitlines(True)
1489 else:
1460 else:
1490 return infile
1461 return infile
1491 # UTF16 - have to decode
1462 # UTF16 - have to decode
1492 return self._decode(infile, encoding)
1463 return self._decode(infile, encoding)
1493
1464
1494 # No BOM discovered and no encoding specified, just return
1465 # No BOM discovered and no encoding specified, just return
1495 if isinstance(infile, StringTypes):
1466 if isinstance(infile, StringTypes):
1496 # infile read from a file will be a single string
1467 # infile read from a file will be a single string
1497 return infile.splitlines(True)
1468 return infile.splitlines(True)
1498 return infile
1469 return infile
1499
1470
1500
1471
1501 def _a_to_u(self, aString):
1472 def _a_to_u(self, aString):
1502 """Decode ASCII strings to unicode if a self.encoding is specified."""
1473 """Decode ASCII strings to unicode if a self.encoding is specified."""
1503 if self.encoding:
1474 if self.encoding:
1504 return aString.decode('ascii')
1475 return aString.decode('ascii')
1505 else:
1476 else:
1506 return aString
1477 return aString
1507
1478
1508
1479
1509 def _decode(self, infile, encoding):
1480 def _decode(self, infile, encoding):
1510 """
1481 """
1511 Decode infile to unicode. Using the specified encoding.
1482 Decode infile to unicode. Using the specified encoding.
1512
1483
1513 if is a string, it also needs converting to a list.
1484 if is a string, it also needs converting to a list.
1514 """
1485 """
1515 if isinstance(infile, StringTypes):
1486 if isinstance(infile, StringTypes):
1516 # can't be unicode
1487 # can't be unicode
1517 # NOTE: Could raise a ``UnicodeDecodeError``
1488 # NOTE: Could raise a ``UnicodeDecodeError``
1518 return infile.decode(encoding).splitlines(True)
1489 return infile.decode(encoding).splitlines(True)
1519 for i, line in enumerate(infile):
1490 for i, line in enumerate(infile):
1520 if not isinstance(line, unicode):
1491 if not isinstance(line, unicode):
1521 # NOTE: The isinstance test here handles mixed lists of unicode/string
1492 # NOTE: The isinstance test here handles mixed lists of unicode/string
1522 # NOTE: But the decode will break on any non-string values
1493 # NOTE: But the decode will break on any non-string values
1523 # NOTE: Or could raise a ``UnicodeDecodeError``
1494 # NOTE: Or could raise a ``UnicodeDecodeError``
1524 infile[i] = line.decode(encoding)
1495 infile[i] = line.decode(encoding)
1525 return infile
1496 return infile
1526
1497
1527
1498
1528 def _decode_element(self, line):
1499 def _decode_element(self, line):
1529 """Decode element to unicode if necessary."""
1500 """Decode element to unicode if necessary."""
1530 if not self.encoding:
1501 if not self.encoding:
1531 return line
1502 return line
1532 if isinstance(line, str) and self.default_encoding:
1503 if isinstance(line, str) and self.default_encoding:
1533 return line.decode(self.default_encoding)
1504 return line.decode(self.default_encoding)
1534 return line
1505 return line
1535
1506
1536
1507
1537 def _str(self, value):
1508 def _str(self, value):
1538 """
1509 """
1539 Used by ``stringify`` within validate, to turn non-string values
1510 Used by ``stringify`` within validate, to turn non-string values
1540 into strings.
1511 into strings.
1541 """
1512 """
1542 if not isinstance(value, StringTypes):
1513 if not isinstance(value, StringTypes):
1543 return str(value)
1514 return str(value)
1544 else:
1515 else:
1545 return value
1516 return value
1546
1517
1547
1518
1548 def _parse(self, infile):
1519 def _parse(self, infile):
1549 """Actually parse the config file."""
1520 """Actually parse the config file."""
1550 temp_list_values = self.list_values
1521 temp_list_values = self.list_values
1551 if self.unrepr:
1522 if self.unrepr:
1552 self.list_values = False
1523 self.list_values = False
1553
1524
1554 comment_list = []
1525 comment_list = []
1555 done_start = False
1526 done_start = False
1556 this_section = self
1527 this_section = self
1557 maxline = len(infile) - 1
1528 maxline = len(infile) - 1
1558 cur_index = -1
1529 cur_index = -1
1559 reset_comment = False
1530 reset_comment = False
1560
1531
1561 while cur_index < maxline:
1532 while cur_index < maxline:
1562 if reset_comment:
1533 if reset_comment:
1563 comment_list = []
1534 comment_list = []
1564 cur_index += 1
1535 cur_index += 1
1565 line = infile[cur_index]
1536 line = infile[cur_index]
1566 sline = line.strip()
1537 sline = line.strip()
1567 # do we have anything on the line ?
1538 # do we have anything on the line ?
1568 if not sline or sline.startswith('#'):
1539 if not sline or sline.startswith('#'):
1569 reset_comment = False
1540 reset_comment = False
1570 comment_list.append(line)
1541 comment_list.append(line)
1571 continue
1542 continue
1572
1543
1573 if not done_start:
1544 if not done_start:
1574 # preserve initial comment
1545 # preserve initial comment
1575 self.initial_comment = comment_list
1546 self.initial_comment = comment_list
1576 comment_list = []
1547 comment_list = []
1577 done_start = True
1548 done_start = True
1578
1549
1579 reset_comment = True
1550 reset_comment = True
1580 # first we check if it's a section marker
1551 # first we check if it's a section marker
1581 mat = self._sectionmarker.match(line)
1552 mat = self._sectionmarker.match(line)
1582 if mat is not None:
1553 if mat is not None:
1583 # is a section line
1554 # is a section line
1584 (indent, sect_open, sect_name, sect_close, comment) = mat.groups()
1555 (indent, sect_open, sect_name, sect_close, comment) = mat.groups()
1585 if indent and (self.indent_type is None):
1556 if indent and (self.indent_type is None):
1586 self.indent_type = indent
1557 self.indent_type = indent
1587 cur_depth = sect_open.count('[')
1558 cur_depth = sect_open.count('[')
1588 if cur_depth != sect_close.count(']'):
1559 if cur_depth != sect_close.count(']'):
1589 self._handle_error("Cannot compute the section depth at line %s.",
1560 self._handle_error("Cannot compute the section depth at line %s.",
1590 NestingError, infile, cur_index)
1561 NestingError, infile, cur_index)
1591 continue
1562 continue
1592
1563
1593 if cur_depth < this_section.depth:
1564 if cur_depth < this_section.depth:
1594 # the new section is dropping back to a previous level
1565 # the new section is dropping back to a previous level
1595 try:
1566 try:
1596 parent = self._match_depth(this_section,
1567 parent = self._match_depth(this_section,
1597 cur_depth).parent
1568 cur_depth).parent
1598 except SyntaxError:
1569 except SyntaxError:
1599 self._handle_error("Cannot compute nesting level at line %s.",
1570 self._handle_error("Cannot compute nesting level at line %s.",
1600 NestingError, infile, cur_index)
1571 NestingError, infile, cur_index)
1601 continue
1572 continue
1602 elif cur_depth == this_section.depth:
1573 elif cur_depth == this_section.depth:
1603 # the new section is a sibling of the current section
1574 # the new section is a sibling of the current section
1604 parent = this_section.parent
1575 parent = this_section.parent
1605 elif cur_depth == this_section.depth + 1:
1576 elif cur_depth == this_section.depth + 1:
1606 # the new section is a child the current section
1577 # the new section is a child the current section
1607 parent = this_section
1578 parent = this_section
1608 else:
1579 else:
1609 self._handle_error("Section too nested at line %s.",
1580 self._handle_error("Section too nested at line %s.",
1610 NestingError, infile, cur_index)
1581 NestingError, infile, cur_index)
1611
1582
1612 sect_name = self._unquote(sect_name)
1583 sect_name = self._unquote(sect_name)
1613 if parent.has_key(sect_name):
1584 if parent.has_key(sect_name):
1614 self._handle_error('Duplicate section name at line %s.',
1585 self._handle_error('Duplicate section name at line %s.',
1615 DuplicateError, infile, cur_index)
1586 DuplicateError, infile, cur_index)
1616 continue
1587 continue
1617
1588
1618 # create the new section
1589 # create the new section
1619 this_section = Section(
1590 this_section = Section(
1620 parent,
1591 parent,
1621 cur_depth,
1592 cur_depth,
1622 self,
1593 self,
1623 name=sect_name)
1594 name=sect_name)
1624 parent[sect_name] = this_section
1595 parent[sect_name] = this_section
1625 parent.inline_comments[sect_name] = comment
1596 parent.inline_comments[sect_name] = comment
1626 parent.comments[sect_name] = comment_list
1597 parent.comments[sect_name] = comment_list
1627 continue
1598 continue
1628 #
1599 #
1629 # it's not a section marker,
1600 # it's not a section marker,
1630 # so it should be a valid ``key = value`` line
1601 # so it should be a valid ``key = value`` line
1631 mat = self._keyword.match(line)
1602 mat = self._keyword.match(line)
1632 if mat is None:
1603 if mat is None:
1633 # it neither matched as a keyword
1604 # it neither matched as a keyword
1634 # or a section marker
1605 # or a section marker
1635 self._handle_error(
1606 self._handle_error(
1636 'Invalid line at line "%s".',
1607 'Invalid line at line "%s".',
1637 ParseError, infile, cur_index)
1608 ParseError, infile, cur_index)
1638 else:
1609 else:
1639 # is a keyword value
1610 # is a keyword value
1640 # value will include any inline comment
1611 # value will include any inline comment
1641 (indent, key, value) = mat.groups()
1612 (indent, key, value) = mat.groups()
1642 if indent and (self.indent_type is None):
1613 if indent and (self.indent_type is None):
1643 self.indent_type = indent
1614 self.indent_type = indent
1644 # check for a multiline value
1615 # check for a multiline value
1645 if value[:3] in ['"""', "'''"]:
1616 if value[:3] in ['"""', "'''"]:
1646 try:
1617 try:
1647 (value, comment, cur_index) = self._multiline(
1618 (value, comment, cur_index) = self._multiline(
1648 value, infile, cur_index, maxline)
1619 value, infile, cur_index, maxline)
1649 except SyntaxError:
1620 except SyntaxError:
1650 self._handle_error(
1621 self._handle_error(
1651 'Parse error in value at line %s.',
1622 'Parse error in value at line %s.',
1652 ParseError, infile, cur_index)
1623 ParseError, infile, cur_index)
1653 continue
1624 continue
1654 else:
1625 else:
1655 if self.unrepr:
1626 if self.unrepr:
1656 comment = ''
1627 comment = ''
1657 try:
1628 try:
1658 value = unrepr(value)
1629 value = unrepr(value)
1659 except Exception, e:
1630 except Exception, e:
1660 if type(e) == UnknownType:
1631 if type(e) == UnknownType:
1661 msg = 'Unknown name or type in value at line %s.'
1632 msg = 'Unknown name or type in value at line %s.'
1662 else:
1633 else:
1663 msg = 'Parse error in value at line %s.'
1634 msg = 'Parse error in value at line %s.'
1664 self._handle_error(msg, UnreprError, infile,
1635 self._handle_error(msg, UnreprError, infile,
1665 cur_index)
1636 cur_index)
1666 continue
1637 continue
1667 else:
1638 else:
1668 if self.unrepr:
1639 if self.unrepr:
1669 comment = ''
1640 comment = ''
1670 try:
1641 try:
1671 value = unrepr(value)
1642 value = unrepr(value)
1672 except Exception, e:
1643 except Exception, e:
1673 if isinstance(e, UnknownType):
1644 if isinstance(e, UnknownType):
1674 msg = 'Unknown name or type in value at line %s.'
1645 msg = 'Unknown name or type in value at line %s.'
1675 else:
1646 else:
1676 msg = 'Parse error in value at line %s.'
1647 msg = 'Parse error in value at line %s.'
1677 self._handle_error(msg, UnreprError, infile,
1648 self._handle_error(msg, UnreprError, infile,
1678 cur_index)
1649 cur_index)
1679 continue
1650 continue
1680 else:
1651 else:
1681 # extract comment and lists
1652 # extract comment and lists
1682 try:
1653 try:
1683 (value, comment) = self._handle_value(value)
1654 (value, comment) = self._handle_value(value)
1684 except SyntaxError:
1655 except SyntaxError:
1685 self._handle_error(
1656 self._handle_error(
1686 'Parse error in value at line %s.',
1657 'Parse error in value at line %s.',
1687 ParseError, infile, cur_index)
1658 ParseError, infile, cur_index)
1688 continue
1659 continue
1689 #
1660 #
1690 key = self._unquote(key)
1661 key = self._unquote(key)
1691 if this_section.has_key(key):
1662 if this_section.has_key(key):
1692 self._handle_error(
1663 self._handle_error(
1693 'Duplicate keyword name at line %s.',
1664 'Duplicate keyword name at line %s.',
1694 DuplicateError, infile, cur_index)
1665 DuplicateError, infile, cur_index)
1695 continue
1666 continue
1696 # add the key.
1667 # add the key.
1697 # we set unrepr because if we have got this far we will never
1668 # we set unrepr because if we have got this far we will never
1698 # be creating a new section
1669 # be creating a new section
1699 this_section.__setitem__(key, value, unrepr=True)
1670 this_section.__setitem__(key, value, unrepr=True)
1700 this_section.inline_comments[key] = comment
1671 this_section.inline_comments[key] = comment
1701 this_section.comments[key] = comment_list
1672 this_section.comments[key] = comment_list
1702 continue
1673 continue
1703 #
1674 #
1704 if self.indent_type is None:
1675 if self.indent_type is None:
1705 # no indentation used, set the type accordingly
1676 # no indentation used, set the type accordingly
1706 self.indent_type = ''
1677 self.indent_type = ''
1707
1678
1708 # preserve the final comment
1679 # preserve the final comment
1709 if not self and not self.initial_comment:
1680 if not self and not self.initial_comment:
1710 self.initial_comment = comment_list
1681 self.initial_comment = comment_list
1711 elif not reset_comment:
1682 elif not reset_comment:
1712 self.final_comment = comment_list
1683 self.final_comment = comment_list
1713 self.list_values = temp_list_values
1684 self.list_values = temp_list_values
1714
1685
1715
1686
1716 def _match_depth(self, sect, depth):
1687 def _match_depth(self, sect, depth):
1717 """
1688 """
1718 Given a section and a depth level, walk back through the sections
1689 Given a section and a depth level, walk back through the sections
1719 parents to see if the depth level matches a previous section.
1690 parents to see if the depth level matches a previous section.
1720
1691
1721 Return a reference to the right section,
1692 Return a reference to the right section,
1722 or raise a SyntaxError.
1693 or raise a SyntaxError.
1723 """
1694 """
1724 while depth < sect.depth:
1695 while depth < sect.depth:
1725 if sect is sect.parent:
1696 if sect is sect.parent:
1726 # we've reached the top level already
1697 # we've reached the top level already
1727 raise SyntaxError()
1698 raise SyntaxError()
1728 sect = sect.parent
1699 sect = sect.parent
1729 if sect.depth == depth:
1700 if sect.depth == depth:
1730 return sect
1701 return sect
1731 # shouldn't get here
1702 # shouldn't get here
1732 raise SyntaxError()
1703 raise SyntaxError()
1733
1704
1734
1705
1735 def _handle_error(self, text, ErrorClass, infile, cur_index):
1706 def _handle_error(self, text, ErrorClass, infile, cur_index):
1736 """
1707 """
1737 Handle an error according to the error settings.
1708 Handle an error according to the error settings.
1738
1709
1739 Either raise the error or store it.
1710 Either raise the error or store it.
1740 The error will have occured at ``cur_index``
1711 The error will have occured at ``cur_index``
1741 """
1712 """
1742 line = infile[cur_index]
1713 line = infile[cur_index]
1743 cur_index += 1
1714 cur_index += 1
1744 message = text % cur_index
1715 message = text % cur_index
1745 error = ErrorClass(message, cur_index, line)
1716 error = ErrorClass(message, cur_index, line)
1746 if self.raise_errors:
1717 if self.raise_errors:
1747 # raise the error - parsing stops here
1718 # raise the error - parsing stops here
1748 raise error
1719 raise error
1749 # store the error
1720 # store the error
1750 # reraise when parsing has finished
1721 # reraise when parsing has finished
1751 self._errors.append(error)
1722 self._errors.append(error)
1752
1723
1753
1724
1754 def _unquote(self, value):
1725 def _unquote(self, value):
1755 """Return an unquoted version of a value"""
1726 """Return an unquoted version of a value"""
1756 if (value[0] == value[-1]) and (value[0] in ('"', "'")):
1727 if (value[0] == value[-1]) and (value[0] in ('"', "'")):
1757 value = value[1:-1]
1728 value = value[1:-1]
1758 return value
1729 return value
1759
1730
1760
1731
1761 def _quote(self, value, multiline=True):
1732 def _quote(self, value, multiline=True):
1762 """
1733 """
1763 Return a safely quoted version of a value.
1734 Return a safely quoted version of a value.
1764
1735
1765 Raise a ConfigObjError if the value cannot be safely quoted.
1736 Raise a ConfigObjError if the value cannot be safely quoted.
1766 If multiline is ``True`` (default) then use triple quotes
1737 If multiline is ``True`` (default) then use triple quotes
1767 if necessary.
1738 if necessary.
1768
1739
1769 Don't quote values that don't need it.
1740 Don't quote values that don't need it.
1770 Recursively quote members of a list and return a comma joined list.
1741 Recursively quote members of a list and return a comma joined list.
1771 Multiline is ``False`` for lists.
1742 Multiline is ``False`` for lists.
1772 Obey list syntax for empty and single member lists.
1743 Obey list syntax for empty and single member lists.
1773
1744
1774 If ``list_values=False`` then the value is only quoted if it contains
1745 If ``list_values=False`` then the value is only quoted if it contains
1775 a ``\n`` (is multiline) or '#'.
1746 a ``\n`` (is multiline) or '#'.
1776
1747
1777 If ``write_empty_values`` is set, and the value is an empty string, it
1748 If ``write_empty_values`` is set, and the value is an empty string, it
1778 won't be quoted.
1749 won't be quoted.
1779 """
1750 """
1780 if multiline and self.write_empty_values and value == '':
1751 if multiline and self.write_empty_values and value == '':
1781 # Only if multiline is set, so that it is used for values not
1752 # Only if multiline is set, so that it is used for values not
1782 # keys, and not values that are part of a list
1753 # keys, and not values that are part of a list
1783 return ''
1754 return ''
1784
1755
1785 if multiline and isinstance(value, (list, tuple)):
1756 if multiline and isinstance(value, (list, tuple)):
1786 if not value:
1757 if not value:
1787 return ','
1758 return ','
1788 elif len(value) == 1:
1759 elif len(value) == 1:
1789 return self._quote(value[0], multiline=False) + ','
1760 return self._quote(value[0], multiline=False) + ','
1790 return ', '.join([self._quote(val, multiline=False)
1761 return ', '.join([self._quote(val, multiline=False)
1791 for val in value])
1762 for val in value])
1792 if not isinstance(value, StringTypes):
1763 if not isinstance(value, StringTypes):
1793 if self.stringify:
1764 if self.stringify:
1794 value = str(value)
1765 value = str(value)
1795 else:
1766 else:
1796 raise TypeError('Value "%s" is not a string.' % value)
1767 raise TypeError('Value "%s" is not a string.' % value)
1797
1768
1798 if not value:
1769 if not value:
1799 return '""'
1770 return '""'
1800
1771
1801 no_lists_no_quotes = not self.list_values and '\n' not in value and '#' not in value
1772 no_lists_no_quotes = not self.list_values and '\n' not in value and '#' not in value
1802 need_triple = multiline and ((("'" in value) and ('"' in value)) or ('\n' in value ))
1773 need_triple = multiline and ((("'" in value) and ('"' in value)) or ('\n' in value ))
1803 hash_triple_quote = multiline and not need_triple and ("'" in value) and ('"' in value) and ('#' in value)
1774 hash_triple_quote = multiline and not need_triple and ("'" in value) and ('"' in value) and ('#' in value)
1804 check_for_single = (no_lists_no_quotes or not need_triple) and not hash_triple_quote
1775 check_for_single = (no_lists_no_quotes or not need_triple) and not hash_triple_quote
1805
1776
1806 if check_for_single:
1777 if check_for_single:
1807 if not self.list_values:
1778 if not self.list_values:
1808 # we don't quote if ``list_values=False``
1779 # we don't quote if ``list_values=False``
1809 quot = noquot
1780 quot = noquot
1810 # for normal values either single or double quotes will do
1781 # for normal values either single or double quotes will do
1811 elif '\n' in value:
1782 elif '\n' in value:
1812 # will only happen if multiline is off - e.g. '\n' in key
1783 # will only happen if multiline is off - e.g. '\n' in key
1813 raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1784 raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1814 elif ((value[0] not in wspace_plus) and
1785 elif ((value[0] not in wspace_plus) and
1815 (value[-1] not in wspace_plus) and
1786 (value[-1] not in wspace_plus) and
1816 (',' not in value)):
1787 (',' not in value)):
1817 quot = noquot
1788 quot = noquot
1818 else:
1789 else:
1819 quot = self._get_single_quote(value)
1790 quot = self._get_single_quote(value)
1820 else:
1791 else:
1821 # if value has '\n' or "'" *and* '"', it will need triple quotes
1792 # if value has '\n' or "'" *and* '"', it will need triple quotes
1822 quot = self._get_triple_quote(value)
1793 quot = self._get_triple_quote(value)
1823
1794
1824 if quot == noquot and '#' in value and self.list_values:
1795 if quot == noquot and '#' in value and self.list_values:
1825 quot = self._get_single_quote(value)
1796 quot = self._get_single_quote(value)
1826
1797
1827 return quot % value
1798 return quot % value
1828
1799
1829
1800
1830 def _get_single_quote(self, value):
1801 def _get_single_quote(self, value):
1831 if ("'" in value) and ('"' in value):
1802 if ("'" in value) and ('"' in value):
1832 raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1803 raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1833 elif '"' in value:
1804 elif '"' in value:
1834 quot = squot
1805 quot = squot
1835 else:
1806 else:
1836 quot = dquot
1807 quot = dquot
1837 return quot
1808 return quot
1838
1809
1839
1810
1840 def _get_triple_quote(self, value):
1811 def _get_triple_quote(self, value):
1841 if (value.find('"""') != -1) and (value.find("'''") != -1):
1812 if (value.find('"""') != -1) and (value.find("'''") != -1):
1842 raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1813 raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1843 if value.find('"""') == -1:
1814 if value.find('"""') == -1:
1844 quot = tdquot
1815 quot = tdquot
1845 else:
1816 else:
1846 quot = tsquot
1817 quot = tsquot
1847 return quot
1818 return quot
1848
1819
1849
1820
1850 def _handle_value(self, value):
1821 def _handle_value(self, value):
1851 """
1822 """
1852 Given a value string, unquote, remove comment,
1823 Given a value string, unquote, remove comment,
1853 handle lists. (including empty and single member lists)
1824 handle lists. (including empty and single member lists)
1854 """
1825 """
1855 # do we look for lists in values ?
1826 # do we look for lists in values ?
1856 if not self.list_values:
1827 if not self.list_values:
1857 mat = self._nolistvalue.match(value)
1828 mat = self._nolistvalue.match(value)
1858 if mat is None:
1829 if mat is None:
1859 raise SyntaxError()
1830 raise SyntaxError()
1860 # NOTE: we don't unquote here
1831 # NOTE: we don't unquote here
1861 return mat.groups()
1832 return mat.groups()
1862 #
1833 #
1863 mat = self._valueexp.match(value)
1834 mat = self._valueexp.match(value)
1864 if mat is None:
1835 if mat is None:
1865 # the value is badly constructed, probably badly quoted,
1836 # the value is badly constructed, probably badly quoted,
1866 # or an invalid list
1837 # or an invalid list
1867 raise SyntaxError()
1838 raise SyntaxError()
1868 (list_values, single, empty_list, comment) = mat.groups()
1839 (list_values, single, empty_list, comment) = mat.groups()
1869 if (list_values == '') and (single is None):
1840 if (list_values == '') and (single is None):
1870 # change this if you want to accept empty values
1841 # change this if you want to accept empty values
1871 raise SyntaxError()
1842 raise SyntaxError()
1872 # NOTE: note there is no error handling from here if the regex
1843 # NOTE: note there is no error handling from here if the regex
1873 # is wrong: then incorrect values will slip through
1844 # is wrong: then incorrect values will slip through
1874 if empty_list is not None:
1845 if empty_list is not None:
1875 # the single comma - meaning an empty list
1846 # the single comma - meaning an empty list
1876 return ([], comment)
1847 return ([], comment)
1877 if single is not None:
1848 if single is not None:
1878 # handle empty values
1849 # handle empty values
1879 if list_values and not single:
1850 if list_values and not single:
1880 # FIXME: the '' is a workaround because our regex now matches
1851 # FIXME: the '' is a workaround because our regex now matches
1881 # '' at the end of a list if it has a trailing comma
1852 # '' at the end of a list if it has a trailing comma
1882 single = None
1853 single = None
1883 else:
1854 else:
1884 single = single or '""'
1855 single = single or '""'
1885 single = self._unquote(single)
1856 single = self._unquote(single)
1886 if list_values == '':
1857 if list_values == '':
1887 # not a list value
1858 # not a list value
1888 return (single, comment)
1859 return (single, comment)
1889 the_list = self._listvalueexp.findall(list_values)
1860 the_list = self._listvalueexp.findall(list_values)
1890 the_list = [self._unquote(val) for val in the_list]
1861 the_list = [self._unquote(val) for val in the_list]
1891 if single is not None:
1862 if single is not None:
1892 the_list += [single]
1863 the_list += [single]
1893 return (the_list, comment)
1864 return (the_list, comment)
1894
1865
1895
1866
1896 def _multiline(self, value, infile, cur_index, maxline):
1867 def _multiline(self, value, infile, cur_index, maxline):
1897 """Extract the value, where we are in a multiline situation."""
1868 """Extract the value, where we are in a multiline situation."""
1898 quot = value[:3]
1869 quot = value[:3]
1899 newvalue = value[3:]
1870 newvalue = value[3:]
1900 single_line = self._triple_quote[quot][0]
1871 single_line = self._triple_quote[quot][0]
1901 multi_line = self._triple_quote[quot][1]
1872 multi_line = self._triple_quote[quot][1]
1902 mat = single_line.match(value)
1873 mat = single_line.match(value)
1903 if mat is not None:
1874 if mat is not None:
1904 retval = list(mat.groups())
1875 retval = list(mat.groups())
1905 retval.append(cur_index)
1876 retval.append(cur_index)
1906 return retval
1877 return retval
1907 elif newvalue.find(quot) != -1:
1878 elif newvalue.find(quot) != -1:
1908 # somehow the triple quote is missing
1879 # somehow the triple quote is missing
1909 raise SyntaxError()
1880 raise SyntaxError()
1910 #
1881 #
1911 while cur_index < maxline:
1882 while cur_index < maxline:
1912 cur_index += 1
1883 cur_index += 1
1913 newvalue += '\n'
1884 newvalue += '\n'
1914 line = infile[cur_index]
1885 line = infile[cur_index]
1915 if line.find(quot) == -1:
1886 if line.find(quot) == -1:
1916 newvalue += line
1887 newvalue += line
1917 else:
1888 else:
1918 # end of multiline, process it
1889 # end of multiline, process it
1919 break
1890 break
1920 else:
1891 else:
1921 # we've got to the end of the config, oops...
1892 # we've got to the end of the config, oops...
1922 raise SyntaxError()
1893 raise SyntaxError()
1923 mat = multi_line.match(line)
1894 mat = multi_line.match(line)
1924 if mat is None:
1895 if mat is None:
1925 # a badly formed line
1896 # a badly formed line
1926 raise SyntaxError()
1897 raise SyntaxError()
1927 (value, comment) = mat.groups()
1898 (value, comment) = mat.groups()
1928 return (newvalue + value, comment, cur_index)
1899 return (newvalue + value, comment, cur_index)
1929
1900
1930
1901
1931 def _handle_configspec(self, configspec):
1902 def _handle_configspec(self, configspec):
1932 """Parse the configspec."""
1903 """Parse the configspec."""
1933 # FIXME: Should we check that the configspec was created with the
1904 # FIXME: Should we check that the configspec was created with the
1934 # correct settings ? (i.e. ``list_values=False``)
1905 # correct settings ? (i.e. ``list_values=False``)
1935 if not isinstance(configspec, ConfigObj):
1906 if not isinstance(configspec, ConfigObj):
1936 try:
1907 try:
1937 configspec = ConfigObj(configspec,
1908 configspec = ConfigObj(configspec,
1938 raise_errors=True,
1909 raise_errors=True,
1939 file_error=True,
1910 file_error=True,
1940 list_values=False)
1911 list_values=False)
1941 except ConfigObjError, e:
1912 except ConfigObjError, e:
1942 # FIXME: Should these errors have a reference
1913 # FIXME: Should these errors have a reference
1943 # to the already parsed ConfigObj ?
1914 # to the already parsed ConfigObj ?
1944 raise ConfigspecError('Parsing configspec failed: %s' % e)
1915 raise ConfigspecError('Parsing configspec failed: %s' % e)
1945 except IOError, e:
1916 except IOError, e:
1946 raise IOError('Reading configspec failed: %s' % e)
1917 raise IOError('Reading configspec failed: %s' % e)
1947
1918
1948 self._set_configspec_value(configspec, self)
1919 self._set_configspec_value(configspec, self)
1949
1920
1950
1921
1951 def _set_configspec_value(self, configspec, section):
1922 def _set_configspec_value(self, configspec, section):
1952 """Used to recursively set configspec values."""
1923 """Used to recursively set configspec values."""
1953 if '__many__' in configspec.sections:
1924 if '__many__' in configspec.sections:
1954 section.configspec['__many__'] = configspec['__many__']
1925 section.configspec['__many__'] = configspec['__many__']
1955 if len(configspec.sections) > 1:
1926 if len(configspec.sections) > 1:
1956 # FIXME: can we supply any useful information here ?
1927 # FIXME: can we supply any useful information here ?
1957 raise RepeatSectionError()
1928 raise RepeatSectionError()
1958
1929
1959 if hasattr(configspec, 'initial_comment'):
1930 if hasattr(configspec, 'initial_comment'):
1960 section._configspec_initial_comment = configspec.initial_comment
1931 section._configspec_initial_comment = configspec.initial_comment
1961 section._configspec_final_comment = configspec.final_comment
1932 section._configspec_final_comment = configspec.final_comment
1962 section._configspec_encoding = configspec.encoding
1933 section._configspec_encoding = configspec.encoding
1963 section._configspec_BOM = configspec.BOM
1934 section._configspec_BOM = configspec.BOM
1964 section._configspec_newlines = configspec.newlines
1935 section._configspec_newlines = configspec.newlines
1965 section._configspec_indent_type = configspec.indent_type
1936 section._configspec_indent_type = configspec.indent_type
1966
1937
1967 for entry in configspec.scalars:
1938 for entry in configspec.scalars:
1968 section._configspec_comments[entry] = configspec.comments[entry]
1939 section._configspec_comments[entry] = configspec.comments[entry]
1969 section._configspec_inline_comments[entry] = configspec.inline_comments[entry]
1940 section._configspec_inline_comments[entry] = configspec.inline_comments[entry]
1970 section.configspec[entry] = configspec[entry]
1941 section.configspec[entry] = configspec[entry]
1971 section._order.append(entry)
1942 section._order.append(entry)
1972
1943
1973 for entry in configspec.sections:
1944 for entry in configspec.sections:
1974 if entry == '__many__':
1945 if entry == '__many__':
1975 continue
1946 continue
1976
1947
1977 section._cs_section_comments[entry] = configspec.comments[entry]
1948 section._cs_section_comments[entry] = configspec.comments[entry]
1978 section._cs_section_inline_comments[entry] = configspec.inline_comments[entry]
1949 section._cs_section_inline_comments[entry] = configspec.inline_comments[entry]
1979 if not section.has_key(entry):
1950 if not section.has_key(entry):
1980 section[entry] = {}
1951 section[entry] = {}
1981 self._set_configspec_value(configspec[entry], section[entry])
1952 self._set_configspec_value(configspec[entry], section[entry])
1982
1953
1983
1954
1984 def _handle_repeat(self, section, configspec):
1955 def _handle_repeat(self, section, configspec):
1985 """Dynamically assign configspec for repeated section."""
1956 """Dynamically assign configspec for repeated section."""
1986 try:
1957 try:
1987 section_keys = configspec.sections
1958 section_keys = configspec.sections
1988 scalar_keys = configspec.scalars
1959 scalar_keys = configspec.scalars
1989 except AttributeError:
1960 except AttributeError:
1990 section_keys = [entry for entry in configspec
1961 section_keys = [entry for entry in configspec
1991 if isinstance(configspec[entry], dict)]
1962 if isinstance(configspec[entry], dict)]
1992 scalar_keys = [entry for entry in configspec
1963 scalar_keys = [entry for entry in configspec
1993 if not isinstance(configspec[entry], dict)]
1964 if not isinstance(configspec[entry], dict)]
1994
1965
1995 if '__many__' in section_keys and len(section_keys) > 1:
1966 if '__many__' in section_keys and len(section_keys) > 1:
1996 # FIXME: can we supply any useful information here ?
1967 # FIXME: can we supply any useful information here ?
1997 raise RepeatSectionError()
1968 raise RepeatSectionError()
1998
1969
1999 scalars = {}
1970 scalars = {}
2000 sections = {}
1971 sections = {}
2001 for entry in scalar_keys:
1972 for entry in scalar_keys:
2002 val = configspec[entry]
1973 val = configspec[entry]
2003 scalars[entry] = val
1974 scalars[entry] = val
2004 for entry in section_keys:
1975 for entry in section_keys:
2005 val = configspec[entry]
1976 val = configspec[entry]
2006 if entry == '__many__':
1977 if entry == '__many__':
2007 scalars[entry] = val
1978 scalars[entry] = val
2008 continue
1979 continue
2009 sections[entry] = val
1980 sections[entry] = val
2010
1981
2011 section.configspec = scalars
1982 section.configspec = scalars
2012 for entry in sections:
1983 for entry in sections:
2013 if not section.has_key(entry):
1984 if not section.has_key(entry):
2014 section[entry] = {}
1985 section[entry] = {}
2015 self._handle_repeat(section[entry], sections[entry])
1986 self._handle_repeat(section[entry], sections[entry])
2016
1987
2017
1988
2018 def _write_line(self, indent_string, entry, this_entry, comment):
1989 def _write_line(self, indent_string, entry, this_entry, comment):
2019 """Write an individual line, for the write method"""
1990 """Write an individual line, for the write method"""
2020 # NOTE: the calls to self._quote here handles non-StringType values.
1991 # NOTE: the calls to self._quote here handles non-StringType values.
2021 if not self.unrepr:
1992 if not self.unrepr:
2022 val = self._decode_element(self._quote(this_entry))
1993 val = self._decode_element(self._quote(this_entry))
2023 else:
1994 else:
2024 val = repr(this_entry)
1995 val = repr(this_entry)
2025 return '%s%s%s%s%s' % (indent_string,
1996 return '%s%s%s%s%s' % (indent_string,
2026 self._decode_element(self._quote(entry, multiline=False)),
1997 self._decode_element(self._quote(entry, multiline=False)),
2027 self._a_to_u(' = '),
1998 self._a_to_u(' = '),
2028 val,
1999 val,
2029 self._decode_element(comment))
2000 self._decode_element(comment))
2030
2001
2031
2002
2032 def _write_marker(self, indent_string, depth, entry, comment):
2003 def _write_marker(self, indent_string, depth, entry, comment):
2033 """Write a section marker line"""
2004 """Write a section marker line"""
2034 return '%s%s%s%s%s' % (indent_string,
2005 return '%s%s%s%s%s' % (indent_string,
2035 self._a_to_u('[' * depth),
2006 self._a_to_u('[' * depth),
2036 self._quote(self._decode_element(entry), multiline=False),
2007 self._quote(self._decode_element(entry), multiline=False),
2037 self._a_to_u(']' * depth),
2008 self._a_to_u(']' * depth),
2038 self._decode_element(comment))
2009 self._decode_element(comment))
2039
2010
2040
2011
2041 def _handle_comment(self, comment):
2012 def _handle_comment(self, comment):
2042 """Deal with a comment."""
2013 """Deal with a comment."""
2043 if not comment:
2014 if not comment:
2044 return ''
2015 return ''
2045 start = self.indent_type
2016 start = self.indent_type
2046 if not comment.startswith('#'):
2017 if not comment.startswith('#'):
2047 start += self._a_to_u(' # ')
2018 start += self._a_to_u(' # ')
2048 return (start + comment)
2019 return (start + comment)
2049
2020
2050
2021
2051 # Public methods
2022 # Public methods
2052
2023
2053 def write(self, outfile=None, section=None):
2024 def write(self, outfile=None, section=None):
2054 """
2025 """
2055 Write the current ConfigObj as a file
2026 Write the current ConfigObj as a file
2056
2027
2057 tekNico: FIXME: use StringIO instead of real files
2028 tekNico: FIXME: use StringIO instead of real files
2058
2029
2059 >>> filename = a.filename
2030 >>> filename = a.filename
2060 >>> a.filename = 'test.ini'
2031 >>> a.filename = 'test.ini'
2061 >>> a.write()
2032 >>> a.write()
2062 >>> a.filename = filename
2033 >>> a.filename = filename
2063 >>> a == ConfigObj('test.ini', raise_errors=True)
2034 >>> a == ConfigObj('test.ini', raise_errors=True)
2064 1
2035 1
2065 """
2036 """
2066 if self.indent_type is None:
2037 if self.indent_type is None:
2067 # this can be true if initialised from a dictionary
2038 # this can be true if initialised from a dictionary
2068 self.indent_type = DEFAULT_INDENT_TYPE
2039 self.indent_type = DEFAULT_INDENT_TYPE
2069
2040
2070 out = []
2041 out = []
2071 cs = self._a_to_u('#')
2042 cs = self._a_to_u('#')
2072 csp = self._a_to_u('# ')
2043 csp = self._a_to_u('# ')
2073 if section is None:
2044 if section is None:
2074 int_val = self.interpolation
2045 int_val = self.interpolation
2075 self.interpolation = False
2046 self.interpolation = False
2076 section = self
2047 section = self
2077 for line in self.initial_comment:
2048 for line in self.initial_comment:
2078 line = self._decode_element(line)
2049 line = self._decode_element(line)
2079 stripped_line = line.strip()
2050 stripped_line = line.strip()
2080 if stripped_line and not stripped_line.startswith(cs):
2051 if stripped_line and not stripped_line.startswith(cs):
2081 line = csp + line
2052 line = csp + line
2082 out.append(line)
2053 out.append(line)
2083
2054
2084 indent_string = self.indent_type * section.depth
2055 indent_string = self.indent_type * section.depth
2085 for entry in (section.scalars + section.sections):
2056 for entry in (section.scalars + section.sections):
2086 if entry in section.defaults:
2057 if entry in section.defaults:
2087 # don't write out default values
2058 # don't write out default values
2088 continue
2059 continue
2089 for comment_line in section.comments[entry]:
2060 for comment_line in section.comments[entry]:
2090 comment_line = self._decode_element(comment_line.lstrip())
2061 comment_line = self._decode_element(comment_line.lstrip())
2091 if comment_line and not comment_line.startswith(cs):
2062 if comment_line and not comment_line.startswith(cs):
2092 comment_line = csp + comment_line
2063 comment_line = csp + comment_line
2093 out.append(indent_string + comment_line)
2064 out.append(indent_string + comment_line)
2094 this_entry = section[entry]
2065 this_entry = section[entry]
2095 comment = self._handle_comment(section.inline_comments[entry])
2066 comment = self._handle_comment(section.inline_comments[entry])
2096
2067
2097 if isinstance(this_entry, dict):
2068 if isinstance(this_entry, dict):
2098 # a section
2069 # a section
2099 out.append(self._write_marker(
2070 out.append(self._write_marker(
2100 indent_string,
2071 indent_string,
2101 this_entry.depth,
2072 this_entry.depth,
2102 entry,
2073 entry,
2103 comment))
2074 comment))
2104 out.extend(self.write(section=this_entry))
2075 out.extend(self.write(section=this_entry))
2105 else:
2076 else:
2106 out.append(self._write_line(
2077 out.append(self._write_line(
2107 indent_string,
2078 indent_string,
2108 entry,
2079 entry,
2109 this_entry,
2080 this_entry,
2110 comment))
2081 comment))
2111
2082
2112 if section is self:
2083 if section is self:
2113 for line in self.final_comment:
2084 for line in self.final_comment:
2114 line = self._decode_element(line)
2085 line = self._decode_element(line)
2115 stripped_line = line.strip()
2086 stripped_line = line.strip()
2116 if stripped_line and not stripped_line.startswith(cs):
2087 if stripped_line and not stripped_line.startswith(cs):
2117 line = csp + line
2088 line = csp + line
2118 out.append(line)
2089 out.append(line)
2119 self.interpolation = int_val
2090 self.interpolation = int_val
2120
2091
2121 if section is not self:
2092 if section is not self:
2122 return out
2093 return out
2123
2094
2124 if (self.filename is None) and (outfile is None):
2095 if (self.filename is None) and (outfile is None):
2125 # output a list of lines
2096 # output a list of lines
2126 # might need to encode
2097 # might need to encode
2127 # NOTE: This will *screw* UTF16, each line will start with the BOM
2098 # NOTE: This will *screw* UTF16, each line will start with the BOM
2128 if self.encoding:
2099 if self.encoding:
2129 out = [l.encode(self.encoding) for l in out]
2100 out = [l.encode(self.encoding) for l in out]
2130 if (self.BOM and ((self.encoding is None) or
2101 if (self.BOM and ((self.encoding is None) or
2131 (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
2102 (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
2132 # Add the UTF8 BOM
2103 # Add the UTF8 BOM
2133 if not out:
2104 if not out:
2134 out.append('')
2105 out.append('')
2135 out[0] = BOM_UTF8 + out[0]
2106 out[0] = BOM_UTF8 + out[0]
2136 return out
2107 return out
2137
2108
2138 # Turn the list to a string, joined with correct newlines
2109 # Turn the list to a string, joined with correct newlines
2139 newline = self.newlines or os.linesep
2110 newline = self.newlines or os.linesep
2140 output = self._a_to_u(newline).join(out)
2111 output = self._a_to_u(newline).join(out)
2141 if self.encoding:
2112 if self.encoding:
2142 output = output.encode(self.encoding)
2113 output = output.encode(self.encoding)
2143 if self.BOM and ((self.encoding is None) or match_utf8(self.encoding)):
2114 if self.BOM and ((self.encoding is None) or match_utf8(self.encoding)):
2144 # Add the UTF8 BOM
2115 # Add the UTF8 BOM
2145 output = BOM_UTF8 + output
2116 output = BOM_UTF8 + output
2146
2117
2147 if not output.endswith(newline):
2118 if not output.endswith(newline):
2148 output += newline
2119 output += newline
2149 if outfile is not None:
2120 if outfile is not None:
2150 outfile.write(output)
2121 outfile.write(output)
2151 else:
2122 else:
2152 h = open(self.filename, 'wb')
2123 h = open(self.filename, 'wb')
2153 h.write(output)
2124 h.write(output)
2154 h.close()
2125 h.close()
2155
2126
2156
2127
2157 def validate(self, validator, preserve_errors=False, copy=False,
2128 def validate(self, validator, preserve_errors=False, copy=False,
2158 section=None):
2129 section=None):
2159 """
2130 """
2160 Test the ConfigObj against a configspec.
2131 Test the ConfigObj against a configspec.
2161
2132
2162 It uses the ``validator`` object from *validate.py*.
2133 It uses the ``validator`` object from *validate.py*.
2163
2134
2164 To run ``validate`` on the current ConfigObj, call: ::
2135 To run ``validate`` on the current ConfigObj, call: ::
2165
2136
2166 test = config.validate(validator)
2137 test = config.validate(validator)
2167
2138
2168 (Normally having previously passed in the configspec when the ConfigObj
2139 (Normally having previously passed in the configspec when the ConfigObj
2169 was created - you can dynamically assign a dictionary of checks to the
2140 was created - you can dynamically assign a dictionary of checks to the
2170 ``configspec`` attribute of a section though).
2141 ``configspec`` attribute of a section though).
2171
2142
2172 It returns ``True`` if everything passes, or a dictionary of
2143 It returns ``True`` if everything passes, or a dictionary of
2173 pass/fails (True/False). If every member of a subsection passes, it
2144 pass/fails (True/False). If every member of a subsection passes, it
2174 will just have the value ``True``. (It also returns ``False`` if all
2145 will just have the value ``True``. (It also returns ``False`` if all
2175 members fail).
2146 members fail).
2176
2147
2177 In addition, it converts the values from strings to their native
2148 In addition, it converts the values from strings to their native
2178 types if their checks pass (and ``stringify`` is set).
2149 types if their checks pass (and ``stringify`` is set).
2179
2150
2180 If ``preserve_errors`` is ``True`` (``False`` is default) then instead
2151 If ``preserve_errors`` is ``True`` (``False`` is default) then instead
2181 of a marking a fail with a ``False``, it will preserve the actual
2152 of a marking a fail with a ``False``, it will preserve the actual
2182 exception object. This can contain info about the reason for failure.
2153 exception object. This can contain info about the reason for failure.
2183 For example the ``VdtValueTooSmallError`` indicates that the value
2154 For example the ``VdtValueTooSmallError`` indicates that the value
2184 supplied was too small. If a value (or section) is missing it will
2155 supplied was too small. If a value (or section) is missing it will
2185 still be marked as ``False``.
2156 still be marked as ``False``.
2186
2157
2187 You must have the validate module to use ``preserve_errors=True``.
2158 You must have the validate module to use ``preserve_errors=True``.
2188
2159
2189 You can then use the ``flatten_errors`` function to turn your nested
2160 You can then use the ``flatten_errors`` function to turn your nested
2190 results dictionary into a flattened list of failures - useful for
2161 results dictionary into a flattened list of failures - useful for
2191 displaying meaningful error messages.
2162 displaying meaningful error messages.
2192 """
2163 """
2193 if section is None:
2164 if section is None:
2194 if self.configspec is None:
2165 if self.configspec is None:
2195 raise ValueError('No configspec supplied.')
2166 raise ValueError('No configspec supplied.')
2196 if preserve_errors:
2167 if preserve_errors:
2197 # We do this once to remove a top level dependency on the validate module
2168 # We do this once to remove a top level dependency on the validate module
2198 # Which makes importing configobj faster
2169 # Which makes importing configobj faster
2199 from validate import VdtMissingValue
2170 from validate import VdtMissingValue
2200 self._vdtMissingValue = VdtMissingValue
2171 self._vdtMissingValue = VdtMissingValue
2201 section = self
2172 section = self
2202 #
2173 #
2203 spec_section = section.configspec
2174 spec_section = section.configspec
2204 if copy and hasattr(section, '_configspec_initial_comment'):
2175 if copy and hasattr(section, '_configspec_initial_comment'):
2205 section.initial_comment = section._configspec_initial_comment
2176 section.initial_comment = section._configspec_initial_comment
2206 section.final_comment = section._configspec_final_comment
2177 section.final_comment = section._configspec_final_comment
2207 section.encoding = section._configspec_encoding
2178 section.encoding = section._configspec_encoding
2208 section.BOM = section._configspec_BOM
2179 section.BOM = section._configspec_BOM
2209 section.newlines = section._configspec_newlines
2180 section.newlines = section._configspec_newlines
2210 section.indent_type = section._configspec_indent_type
2181 section.indent_type = section._configspec_indent_type
2211
2182
2212 if '__many__' in section.configspec:
2183 if '__many__' in section.configspec:
2213 many = spec_section['__many__']
2184 many = spec_section['__many__']
2214 # dynamically assign the configspecs
2185 # dynamically assign the configspecs
2215 # for the sections below
2186 # for the sections below
2216 for entry in section.sections:
2187 for entry in section.sections:
2217 self._handle_repeat(section[entry], many)
2188 self._handle_repeat(section[entry], many)
2218 #
2189 #
2219 out = {}
2190 out = {}
2220 ret_true = True
2191 ret_true = True
2221 ret_false = True
2192 ret_false = True
2222 order = [k for k in section._order if k in spec_section]
2193 order = [k for k in section._order if k in spec_section]
2223 order += [k for k in spec_section if k not in order]
2194 order += [k for k in spec_section if k not in order]
2224 for entry in order:
2195 for entry in order:
2225 if entry == '__many__':
2196 if entry == '__many__':
2226 continue
2197 continue
2227 if (not entry in section.scalars) or (entry in section.defaults):
2198 if (not entry in section.scalars) or (entry in section.defaults):
2228 # missing entries
2199 # missing entries
2229 # or entries from defaults
2200 # or entries from defaults
2230 missing = True
2201 missing = True
2231 val = None
2202 val = None
2232 if copy and not entry in section.scalars:
2203 if copy and not entry in section.scalars:
2233 # copy comments
2204 # copy comments
2234 section.comments[entry] = (
2205 section.comments[entry] = (
2235 section._configspec_comments.get(entry, []))
2206 section._configspec_comments.get(entry, []))
2236 section.inline_comments[entry] = (
2207 section.inline_comments[entry] = (
2237 section._configspec_inline_comments.get(entry, ''))
2208 section._configspec_inline_comments.get(entry, ''))
2238 #
2209 #
2239 else:
2210 else:
2240 missing = False
2211 missing = False
2241 val = section[entry]
2212 val = section[entry]
2242 try:
2213 try:
2243 check = validator.check(spec_section[entry],
2214 check = validator.check(spec_section[entry],
2244 val,
2215 val,
2245 missing=missing
2216 missing=missing
2246 )
2217 )
2247 except validator.baseErrorClass, e:
2218 except validator.baseErrorClass, e:
2248 if not preserve_errors or isinstance(e, self._vdtMissingValue):
2219 if not preserve_errors or isinstance(e, self._vdtMissingValue):
2249 out[entry] = False
2220 out[entry] = False
2250 else:
2221 else:
2251 # preserve the error
2222 # preserve the error
2252 out[entry] = e
2223 out[entry] = e
2253 ret_false = False
2224 ret_false = False
2254 ret_true = False
2225 ret_true = False
2255 else:
2226 else:
2256 try:
2227 try:
2257 section.default_values.pop(entry, None)
2228 section.default_values.pop(entry, None)
2258 except AttributeError:
2229 except AttributeError:
2259 # For Python 2.2 compatibility
2230 # For Python 2.2 compatibility
2260 try:
2231 try:
2261 del section.default_values[entry]
2232 del section.default_values[entry]
2262 except KeyError:
2233 except KeyError:
2263 pass
2234 pass
2264
2235
2265 if hasattr(validator, 'get_default_value'):
2236 if hasattr(validator, 'get_default_value'):
2266 try:
2237 try:
2267 section.default_values[entry] = validator.get_default_value(spec_section[entry])
2238 section.default_values[entry] = validator.get_default_value(spec_section[entry])
2268 except KeyError:
2239 except KeyError:
2269 # No default
2240 # No default
2270 pass
2241 pass
2271
2242
2272 ret_false = False
2243 ret_false = False
2273 out[entry] = True
2244 out[entry] = True
2274 if self.stringify or missing:
2245 if self.stringify or missing:
2275 # if we are doing type conversion
2246 # if we are doing type conversion
2276 # or the value is a supplied default
2247 # or the value is a supplied default
2277 if not self.stringify:
2248 if not self.stringify:
2278 if isinstance(check, (list, tuple)):
2249 if isinstance(check, (list, tuple)):
2279 # preserve lists
2250 # preserve lists
2280 check = [self._str(item) for item in check]
2251 check = [self._str(item) for item in check]
2281 elif missing and check is None:
2252 elif missing and check is None:
2282 # convert the None from a default to a ''
2253 # convert the None from a default to a ''
2283 check = ''
2254 check = ''
2284 else:
2255 else:
2285 check = self._str(check)
2256 check = self._str(check)
2286 if (check != val) or missing:
2257 if (check != val) or missing:
2287 section[entry] = check
2258 section[entry] = check
2288 if not copy and missing and entry not in section.defaults:
2259 if not copy and missing and entry not in section.defaults:
2289 section.defaults.append(entry)
2260 section.defaults.append(entry)
2290 # Missing sections will have been created as empty ones when the
2261 # Missing sections will have been created as empty ones when the
2291 # configspec was read.
2262 # configspec was read.
2292 for entry in section.sections:
2263 for entry in section.sections:
2293 # FIXME: this means DEFAULT is not copied in copy mode
2264 # FIXME: this means DEFAULT is not copied in copy mode
2294 if section is self and entry == 'DEFAULT':
2265 if section is self and entry == 'DEFAULT':
2295 continue
2266 continue
2296 if copy:
2267 if copy:
2297 section.comments[entry] = section._cs_section_comments[entry]
2268 section.comments[entry] = section._cs_section_comments[entry]
2298 section.inline_comments[entry] = (
2269 section.inline_comments[entry] = (
2299 section._cs_section_inline_comments[entry])
2270 section._cs_section_inline_comments[entry])
2300 check = self.validate(validator, preserve_errors=preserve_errors,
2271 check = self.validate(validator, preserve_errors=preserve_errors,
2301 copy=copy, section=section[entry])
2272 copy=copy, section=section[entry])
2302 out[entry] = check
2273 out[entry] = check
2303 if check == False:
2274 if check == False:
2304 ret_true = False
2275 ret_true = False
2305 elif check == True:
2276 elif check == True:
2306 ret_false = False
2277 ret_false = False
2307 else:
2278 else:
2308 ret_true = False
2279 ret_true = False
2309 ret_false = False
2280 ret_false = False
2310 #
2281 #
2311 if ret_true:
2282 if ret_true:
2312 return True
2283 return True
2313 elif ret_false:
2284 elif ret_false:
2314 return False
2285 return False
2315 return out
2286 return out
2316
2287
2317
2288
2318 def reset(self):
2289 def reset(self):
2319 """Clear ConfigObj instance and restore to 'freshly created' state."""
2290 """Clear ConfigObj instance and restore to 'freshly created' state."""
2320 self.clear()
2291 self.clear()
2321 self._initialise()
2292 self._initialise()
2322 # FIXME: Should be done by '_initialise', but ConfigObj constructor (and reload)
2293 # FIXME: Should be done by '_initialise', but ConfigObj constructor (and reload)
2323 # requires an empty dictionary
2294 # requires an empty dictionary
2324 self.configspec = None
2295 self.configspec = None
2325 # Just to be sure ;-)
2296 # Just to be sure ;-)
2326 self._original_configspec = None
2297 self._original_configspec = None
2327
2298
2328
2299
2329 def reload(self):
2300 def reload(self):
2330 """
2301 """
2331 Reload a ConfigObj from file.
2302 Reload a ConfigObj from file.
2332
2303
2333 This method raises a ``ReloadError`` if the ConfigObj doesn't have
2304 This method raises a ``ReloadError`` if the ConfigObj doesn't have
2334 a filename attribute pointing to a file.
2305 a filename attribute pointing to a file.
2335 """
2306 """
2336 if not isinstance(self.filename, StringTypes):
2307 if not isinstance(self.filename, StringTypes):
2337 raise ReloadError()
2308 raise ReloadError()
2338
2309
2339 filename = self.filename
2310 filename = self.filename
2340 current_options = {}
2311 current_options = {}
2341 for entry in OPTION_DEFAULTS:
2312 for entry in OPTION_DEFAULTS:
2342 if entry == 'configspec':
2313 if entry == 'configspec':
2343 continue
2314 continue
2344 current_options[entry] = getattr(self, entry)
2315 current_options[entry] = getattr(self, entry)
2345
2316
2346 configspec = self._original_configspec
2317 configspec = self._original_configspec
2347 current_options['configspec'] = configspec
2318 current_options['configspec'] = configspec
2348
2319
2349 self.clear()
2320 self.clear()
2350 self._initialise(current_options)
2321 self._initialise(current_options)
2351 self._load(filename, configspec)
2322 self._load(filename, configspec)
2352
2323
2353
2324
2354
2325
2355 class SimpleVal(object):
2326 class SimpleVal(object):
2356 """
2327 """
2357 A simple validator.
2328 A simple validator.
2358 Can be used to check that all members expected are present.
2329 Can be used to check that all members expected are present.
2359
2330
2360 To use it, provide a configspec with all your members in (the value given
2331 To use it, provide a configspec with all your members in (the value given
2361 will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
2332 will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
2362 method of your ``ConfigObj``. ``validate`` will return ``True`` if all
2333 method of your ``ConfigObj``. ``validate`` will return ``True`` if all
2363 members are present, or a dictionary with True/False meaning
2334 members are present, or a dictionary with True/False meaning
2364 present/missing. (Whole missing sections will be replaced with ``False``)
2335 present/missing. (Whole missing sections will be replaced with ``False``)
2365 """
2336 """
2366
2337
2367 def __init__(self):
2338 def __init__(self):
2368 self.baseErrorClass = ConfigObjError
2339 self.baseErrorClass = ConfigObjError
2369
2340
2370 def check(self, check, member, missing=False):
2341 def check(self, check, member, missing=False):
2371 """A dummy check method, always returns the value unchanged."""
2342 """A dummy check method, always returns the value unchanged."""
2372 if missing:
2343 if missing:
2373 raise self.baseErrorClass()
2344 raise self.baseErrorClass()
2374 return member
2345 return member
2375
2346
2376
2347
2377 # Check / processing functions for options
2348 # Check / processing functions for options
2378 def flatten_errors(cfg, res, levels=None, results=None):
2349 def flatten_errors(cfg, res, levels=None, results=None):
2379 """
2350 """
2380 An example function that will turn a nested dictionary of results
2351 An example function that will turn a nested dictionary of results
2381 (as returned by ``ConfigObj.validate``) into a flat list.
2352 (as returned by ``ConfigObj.validate``) into a flat list.
2382
2353
2383 ``cfg`` is the ConfigObj instance being checked, ``res`` is the results
2354 ``cfg`` is the ConfigObj instance being checked, ``res`` is the results
2384 dictionary returned by ``validate``.
2355 dictionary returned by ``validate``.
2385
2356
2386 (This is a recursive function, so you shouldn't use the ``levels`` or
2357 (This is a recursive function, so you shouldn't use the ``levels`` or
2387 ``results`` arguments - they are used by the function.
2358 ``results`` arguments - they are used by the function.
2388
2359
2389 Returns a list of keys that failed. Each member of the list is a tuple :
2360 Returns a list of keys that failed. Each member of the list is a tuple :
2390 ::
2361 ::
2391
2362
2392 ([list of sections...], key, result)
2363 ([list of sections...], key, result)
2393
2364
2394 If ``validate`` was called with ``preserve_errors=False`` (the default)
2365 If ``validate`` was called with ``preserve_errors=False`` (the default)
2395 then ``result`` will always be ``False``.
2366 then ``result`` will always be ``False``.
2396
2367
2397 *list of sections* is a flattened list of sections that the key was found
2368 *list of sections* is a flattened list of sections that the key was found
2398 in.
2369 in.
2399
2370
2400 If the section was missing then key will be ``None``.
2371 If the section was missing then key will be ``None``.
2401
2372
2402 If the value (or section) was missing then ``result`` will be ``False``.
2373 If the value (or section) was missing then ``result`` will be ``False``.
2403
2374
2404 If ``validate`` was called with ``preserve_errors=True`` and a value
2375 If ``validate`` was called with ``preserve_errors=True`` and a value
2405 was present, but failed the check, then ``result`` will be the exception
2376 was present, but failed the check, then ``result`` will be the exception
2406 object returned. You can use this as a string that describes the failure.
2377 object returned. You can use this as a string that describes the failure.
2407
2378
2408 For example *The value "3" is of the wrong type*.
2379 For example *The value "3" is of the wrong type*.
2409
2380
2410 >>> import validate
2381 >>> import validate
2411 >>> vtor = validate.Validator()
2382 >>> vtor = validate.Validator()
2412 >>> my_ini = '''
2383 >>> my_ini = '''
2413 ... option1 = True
2384 ... option1 = True
2414 ... [section1]
2385 ... [section1]
2415 ... option1 = True
2386 ... option1 = True
2416 ... [section2]
2387 ... [section2]
2417 ... another_option = Probably
2388 ... another_option = Probably
2418 ... [section3]
2389 ... [section3]
2419 ... another_option = True
2390 ... another_option = True
2420 ... [[section3b]]
2391 ... [[section3b]]
2421 ... value = 3
2392 ... value = 3
2422 ... value2 = a
2393 ... value2 = a
2423 ... value3 = 11
2394 ... value3 = 11
2424 ... '''
2395 ... '''
2425 >>> my_cfg = '''
2396 >>> my_cfg = '''
2426 ... option1 = boolean()
2397 ... option1 = boolean()
2427 ... option2 = boolean()
2398 ... option2 = boolean()
2428 ... option3 = boolean(default=Bad_value)
2399 ... option3 = boolean(default=Bad_value)
2429 ... [section1]
2400 ... [section1]
2430 ... option1 = boolean()
2401 ... option1 = boolean()
2431 ... option2 = boolean()
2402 ... option2 = boolean()
2432 ... option3 = boolean(default=Bad_value)
2403 ... option3 = boolean(default=Bad_value)
2433 ... [section2]
2404 ... [section2]
2434 ... another_option = boolean()
2405 ... another_option = boolean()
2435 ... [section3]
2406 ... [section3]
2436 ... another_option = boolean()
2407 ... another_option = boolean()
2437 ... [[section3b]]
2408 ... [[section3b]]
2438 ... value = integer
2409 ... value = integer
2439 ... value2 = integer
2410 ... value2 = integer
2440 ... value3 = integer(0, 10)
2411 ... value3 = integer(0, 10)
2441 ... [[[section3b-sub]]]
2412 ... [[[section3b-sub]]]
2442 ... value = string
2413 ... value = string
2443 ... [section4]
2414 ... [section4]
2444 ... another_option = boolean()
2415 ... another_option = boolean()
2445 ... '''
2416 ... '''
2446 >>> cs = my_cfg.split('\\n')
2417 >>> cs = my_cfg.split('\\n')
2447 >>> ini = my_ini.split('\\n')
2418 >>> ini = my_ini.split('\\n')
2448 >>> cfg = ConfigObj(ini, configspec=cs)
2419 >>> cfg = ConfigObj(ini, configspec=cs)
2449 >>> res = cfg.validate(vtor, preserve_errors=True)
2420 >>> res = cfg.validate(vtor, preserve_errors=True)
2450 >>> errors = []
2421 >>> errors = []
2451 >>> for entry in flatten_errors(cfg, res):
2422 >>> for entry in flatten_errors(cfg, res):
2452 ... section_list, key, error = entry
2423 ... section_list, key, error = entry
2453 ... section_list.insert(0, '[root]')
2424 ... section_list.insert(0, '[root]')
2454 ... if key is not None:
2425 ... if key is not None:
2455 ... section_list.append(key)
2426 ... section_list.append(key)
2456 ... else:
2427 ... else:
2457 ... section_list.append('[missing]')
2428 ... section_list.append('[missing]')
2458 ... section_string = ', '.join(section_list)
2429 ... section_string = ', '.join(section_list)
2459 ... errors.append((section_string, ' = ', error))
2430 ... errors.append((section_string, ' = ', error))
2460 >>> errors.sort()
2431 >>> errors.sort()
2461 >>> for entry in errors:
2432 >>> for entry in errors:
2462 ... print entry[0], entry[1], (entry[2] or 0)
2433 ... print entry[0], entry[1], (entry[2] or 0)
2463 [root], option2 = 0
2434 [root], option2 = 0
2464 [root], option3 = the value "Bad_value" is of the wrong type.
2435 [root], option3 = the value "Bad_value" is of the wrong type.
2465 [root], section1, option2 = 0
2436 [root], section1, option2 = 0
2466 [root], section1, option3 = the value "Bad_value" is of the wrong type.
2437 [root], section1, option3 = the value "Bad_value" is of the wrong type.
2467 [root], section2, another_option = the value "Probably" is of the wrong type.
2438 [root], section2, another_option = the value "Probably" is of the wrong type.
2468 [root], section3, section3b, section3b-sub, [missing] = 0
2439 [root], section3, section3b, section3b-sub, [missing] = 0
2469 [root], section3, section3b, value2 = the value "a" is of the wrong type.
2440 [root], section3, section3b, value2 = the value "a" is of the wrong type.
2470 [root], section3, section3b, value3 = the value "11" is too big.
2441 [root], section3, section3b, value3 = the value "11" is too big.
2471 [root], section4, [missing] = 0
2442 [root], section4, [missing] = 0
2472 """
2443 """
2473 if levels is None:
2444 if levels is None:
2474 # first time called
2445 # first time called
2475 levels = []
2446 levels = []
2476 results = []
2447 results = []
2477 if res is True:
2448 if res is True:
2478 return results
2449 return results
2479 if res is False:
2450 if res is False:
2480 results.append((levels[:], None, False))
2451 results.append((levels[:], None, False))
2481 if levels:
2452 if levels:
2482 levels.pop()
2453 levels.pop()
2483 return results
2454 return results
2484 for (key, val) in res.items():
2455 for (key, val) in res.iteritems():
2485 if val == True:
2456 if val == True:
2486 continue
2457 continue
2487 if isinstance(cfg.get(key), dict):
2458 if isinstance(cfg.get(key), dict):
2488 # Go down one level
2459 # Go down one level
2489 levels.append(key)
2460 levels.append(key)
2490 flatten_errors(cfg[key], val, levels, results)
2461 flatten_errors(cfg[key], val, levels, results)
2491 continue
2462 continue
2492 results.append((levels[:], key, val))
2463 results.append((levels[:], key, val))
2493 #
2464 #
2494 # Go up one level
2465 # Go up one level
2495 if levels:
2466 if levels:
2496 levels.pop()
2467 levels.pop()
2497 #
2468 #
2498 return results
2469 return results
2499
2470
2500
2471
2501 """*A programming language is a medium of expression.* - Paul Graham"""
2472 """*A programming language is a medium of expression.* - Paul Graham"""
@@ -1,705 +1,692 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 pretty
3 pretty
4 ~~
4 ~~
5
5
6 Python advanced pretty printer. This pretty printer is intended to
6 Python advanced pretty printer. This pretty printer is intended to
7 replace the old `pprint` python module which does not allow developers
7 replace the old `pprint` python module which does not allow developers
8 to provide their own pretty print callbacks.
8 to provide their own pretty print callbacks.
9
9
10 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
10 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
11
11
12
12
13 Example Usage
13 Example Usage
14 =============
14 =============
15
15
16 To directly print the representation of an object use `pprint`::
16 To directly print the representation of an object use `pprint`::
17
17
18 from pretty import pprint
18 from pretty import pprint
19 pprint(complex_object)
19 pprint(complex_object)
20
20
21 To get a string of the output use `pretty`::
21 To get a string of the output use `pretty`::
22
22
23 from pretty import pretty
23 from pretty import pretty
24 string = pretty(complex_object)
24 string = pretty(complex_object)
25
25
26
26
27 Extending
27 Extending
28 =========
28 =========
29
29
30 The pretty library allows developers to add pretty printing rules for their
30 The pretty library allows developers to add pretty printing rules for their
31 own objects. This process is straightforward. All you have to do is to
31 own objects. This process is straightforward. All you have to do is to
32 add a `__pretty__` method to your object and call the methods on the
32 add a `__pretty__` method to your object and call the methods on the
33 pretty printer passed::
33 pretty printer passed::
34
34
35 class MyObject(object):
35 class MyObject(object):
36
36
37 def __pretty__(self, p, cycle):
37 def __pretty__(self, p, cycle):
38 ...
38 ...
39
39
40 Depending on the python version you want to support you have two
40 Depending on the python version you want to support you have two
41 possibilities. The following list shows the python 2.5 version and the
41 possibilities. The following list shows the python 2.5 version and the
42 compatibility one.
42 compatibility one.
43
43
44
44
45 Here the example implementation of a `__pretty__` method for a list
45 Here the example implementation of a `__pretty__` method for a list
46 subclass for python 2.5 and higher (python 2.5 requires the with statement
46 subclass for python 2.5 and higher (python 2.5 requires the with statement
47 __future__ import)::
47 __future__ import)::
48
48
49 class MyList(list):
49 class MyList(list):
50
50
51 def __pretty__(self, p, cycle):
51 def __pretty__(self, p, cycle):
52 if cycle:
52 if cycle:
53 p.text('MyList(...)')
53 p.text('MyList(...)')
54 else:
54 else:
55 with p.group(8, 'MyList([', '])'):
55 with p.group(8, 'MyList([', '])'):
56 for idx, item in enumerate(self):
56 for idx, item in enumerate(self):
57 if idx:
57 if idx:
58 p.text(',')
58 p.text(',')
59 p.breakable()
59 p.breakable()
60 p.pretty(item)
60 p.pretty(item)
61
61
62 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
62 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
63 react to that or the result is an infinite loop. `p.text()` just adds
63 react to that or the result is an infinite loop. `p.text()` just adds
64 non breaking text to the output, `p.breakable()` either adds a whitespace
64 non breaking text to the output, `p.breakable()` either adds a whitespace
65 or breaks here. If you pass it an argument it's used instead of the
65 or breaks here. If you pass it an argument it's used instead of the
66 default space. `p.pretty` prettyprints another object using the pretty print
66 default space. `p.pretty` prettyprints another object using the pretty print
67 method.
67 method.
68
68
69 The first parameter to the `group` function specifies the extra indentation
69 The first parameter to the `group` function specifies the extra indentation
70 of the next line. In this example the next item will either be not
70 of the next line. In this example the next item will either be not
71 breaked (if the items are short enough) or aligned with the right edge of
71 breaked (if the items are short enough) or aligned with the right edge of
72 the opening bracked of `MyList`.
72 the opening bracked of `MyList`.
73
73
74 If you want to support python 2.4 and lower you can use this code::
74 If you want to support python 2.4 and lower you can use this code::
75
75
76 class MyList(list):
76 class MyList(list):
77
77
78 def __pretty__(self, p, cycle):
78 def __pretty__(self, p, cycle):
79 if cycle:
79 if cycle:
80 p.text('MyList(...)')
80 p.text('MyList(...)')
81 else:
81 else:
82 p.begin_group(8, 'MyList([')
82 p.begin_group(8, 'MyList([')
83 for idx, item in enumerate(self):
83 for idx, item in enumerate(self):
84 if idx:
84 if idx:
85 p.text(',')
85 p.text(',')
86 p.breakable()
86 p.breakable()
87 p.pretty(item)
87 p.pretty(item)
88 p.end_group(8, '])')
88 p.end_group(8, '])')
89
89
90 If you just want to indent something you can use the group function
90 If you just want to indent something you can use the group function
91 without open / close parameters. Under python 2.5 you can also use this
91 without open / close parameters. Under python 2.5 you can also use this
92 code::
92 code::
93
93
94 with p.indent(2):
94 with p.indent(2):
95 ...
95 ...
96
96
97 Or under python2.4 you might want to modify ``p.indentation`` by hand but
97 Or under python2.4 you might want to modify ``p.indentation`` by hand but
98 this is rather ugly.
98 this is rather ugly.
99
99
100 :copyright: 2007 by Armin Ronacher.
100 :copyright: 2007 by Armin Ronacher.
101 Portions (c) 2009 by Robert Kern.
101 Portions (c) 2009 by Robert Kern.
102 :license: BSD License.
102 :license: BSD License.
103 """
103 """
104 import __future__
104 import __future__
105 import sys
105 import sys
106 import types
106 import types
107 import re
107 import re
108 import datetime
108 import datetime
109 from StringIO import StringIO
109 from StringIO import StringIO
110 from collections import deque
110 from collections import deque
111
111
112
112
113 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
113 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
114 'for_type', 'for_type_by_name']
114 'for_type', 'for_type_by_name']
115
115
116
116
117 _re_pattern_type = type(re.compile(''))
117 _re_pattern_type = type(re.compile(''))
118
118
119
119
120 def pretty(obj, verbose=False, max_width=79, newline='\n'):
120 def pretty(obj, verbose=False, max_width=79, newline='\n'):
121 """
121 """
122 Pretty print the object's representation.
122 Pretty print the object's representation.
123 """
123 """
124 stream = StringIO()
124 stream = StringIO()
125 printer = RepresentationPrinter(stream, verbose, max_width, newline)
125 printer = RepresentationPrinter(stream, verbose, max_width, newline)
126 printer.pretty(obj)
126 printer.pretty(obj)
127 printer.flush()
127 printer.flush()
128 return stream.getvalue()
128 return stream.getvalue()
129
129
130
130
131 def pprint(obj, verbose=False, max_width=79, newline='\n'):
131 def pprint(obj, verbose=False, max_width=79, newline='\n'):
132 """
132 """
133 Like `pretty` but print to stdout.
133 Like `pretty` but print to stdout.
134 """
134 """
135 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
135 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
136 printer.pretty(obj)
136 printer.pretty(obj)
137 printer.flush()
137 printer.flush()
138 sys.stdout.write(newline)
138 sys.stdout.write(newline)
139 sys.stdout.flush()
139 sys.stdout.flush()
140
140
141
142 # add python2.5 context managers if we have the with statement feature
143 if hasattr(__future__, 'with_statement'): exec '''
144 from __future__ import with_statement
141 from __future__ import with_statement
145 from contextlib import contextmanager
142 from contextlib import contextmanager
146
143
147 class _PrettyPrinterBase(object):
144 class _PrettyPrinterBase(object):
148
145
149 @contextmanager
146 @contextmanager
150 def indent(self, indent):
147 def indent(self, indent):
151 """with statement support for indenting/dedenting."""
148 """with statement support for indenting/dedenting."""
152 self.indentation += indent
149 self.indentation += indent
153 try:
150 try:
154 yield
151 yield
155 finally:
152 finally:
156 self.indentation -= indent
153 self.indentation -= indent
157
154
158 @contextmanager
155 @contextmanager
159 def group(self, indent=0, open='', close=''):
156 def group(self, indent=0, open='', close=''):
160 """like begin_group / end_group but for the with statement."""
157 """like begin_group / end_group but for the with statement."""
161 self.begin_group(indent, open)
158 self.begin_group(indent, open)
162 try:
159 try:
163 with self.indent(indent):
160 with self.indent(indent):
164 yield
161 yield
165 finally:
162 finally:
166 self.end_group(indent, close)
163 self.end_group(indent, close)
167 '''
168 else:
169 class _PrettyPrinterBase(object):
170
171 def _unsupported(self, *a, **kw):
172 """unsupported operation"""
173 raise RuntimeError('not available in this python version')
174 group = indent = _unsupported
175 del _unsupported
176
177
164
178 class PrettyPrinter(_PrettyPrinterBase):
165 class PrettyPrinter(_PrettyPrinterBase):
179 """
166 """
180 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
167 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
181 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
168 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
182 this printer knows nothing about the default pprinters or the `__pretty__`
169 this printer knows nothing about the default pprinters or the `__pretty__`
183 callback method.
170 callback method.
184 """
171 """
185
172
186 def __init__(self, output, max_width=79, newline='\n'):
173 def __init__(self, output, max_width=79, newline='\n'):
187 self.output = output
174 self.output = output
188 self.max_width = max_width
175 self.max_width = max_width
189 self.newline = newline
176 self.newline = newline
190 self.output_width = 0
177 self.output_width = 0
191 self.buffer_width = 0
178 self.buffer_width = 0
192 self.buffer = deque()
179 self.buffer = deque()
193
180
194 root_group = Group(0)
181 root_group = Group(0)
195 self.group_stack = [root_group]
182 self.group_stack = [root_group]
196 self.group_queue = GroupQueue(root_group)
183 self.group_queue = GroupQueue(root_group)
197 self.indentation = 0
184 self.indentation = 0
198
185
199 def _break_outer_groups(self):
186 def _break_outer_groups(self):
200 while self.max_width < self.output_width + self.buffer_width:
187 while self.max_width < self.output_width + self.buffer_width:
201 group = self.group_queue.deq()
188 group = self.group_queue.deq()
202 if not group:
189 if not group:
203 return
190 return
204 while group.breakables:
191 while group.breakables:
205 x = self.buffer.popleft()
192 x = self.buffer.popleft()
206 self.output_width = x.output(self.output, self.output_width)
193 self.output_width = x.output(self.output, self.output_width)
207 self.buffer_width -= x.width
194 self.buffer_width -= x.width
208 while self.buffer and isinstance(self.buffer[0], Text):
195 while self.buffer and isinstance(self.buffer[0], Text):
209 x = self.buffer.popleft()
196 x = self.buffer.popleft()
210 self.output_width = x.output(self.output, self.output_width)
197 self.output_width = x.output(self.output, self.output_width)
211 self.buffer_width -= x.width
198 self.buffer_width -= x.width
212
199
213 def text(self, obj):
200 def text(self, obj):
214 """Add literal text to the output."""
201 """Add literal text to the output."""
215 width = len(obj)
202 width = len(obj)
216 if self.buffer:
203 if self.buffer:
217 text = self.buffer[-1]
204 text = self.buffer[-1]
218 if not isinstance(text, Text):
205 if not isinstance(text, Text):
219 text = Text()
206 text = Text()
220 self.buffer.append(text)
207 self.buffer.append(text)
221 text.add(obj, width)
208 text.add(obj, width)
222 self.buffer_width += width
209 self.buffer_width += width
223 self._break_outer_groups()
210 self._break_outer_groups()
224 else:
211 else:
225 self.output.write(obj)
212 self.output.write(obj)
226 self.output_width += width
213 self.output_width += width
227
214
228 def breakable(self, sep=' '):
215 def breakable(self, sep=' '):
229 """
216 """
230 Add a breakable separator to the output. This does not mean that it
217 Add a breakable separator to the output. This does not mean that it
231 will automatically break here. If no breaking on this position takes
218 will automatically break here. If no breaking on this position takes
232 place the `sep` is inserted which default to one space.
219 place the `sep` is inserted which default to one space.
233 """
220 """
234 width = len(sep)
221 width = len(sep)
235 group = self.group_stack[-1]
222 group = self.group_stack[-1]
236 if group.want_break:
223 if group.want_break:
237 self.flush()
224 self.flush()
238 self.output.write(self.newline)
225 self.output.write(self.newline)
239 self.output.write(' ' * self.indentation)
226 self.output.write(' ' * self.indentation)
240 self.output_width = self.indentation
227 self.output_width = self.indentation
241 self.buffer_width = 0
228 self.buffer_width = 0
242 else:
229 else:
243 self.buffer.append(Breakable(sep, width, self))
230 self.buffer.append(Breakable(sep, width, self))
244 self.buffer_width += width
231 self.buffer_width += width
245 self._break_outer_groups()
232 self._break_outer_groups()
246
233
247
234
248 def begin_group(self, indent=0, open=''):
235 def begin_group(self, indent=0, open=''):
249 """
236 """
250 Begin a group. If you want support for python < 2.5 which doesn't has
237 Begin a group. If you want support for python < 2.5 which doesn't has
251 the with statement this is the preferred way:
238 the with statement this is the preferred way:
252
239
253 p.begin_group(1, '{')
240 p.begin_group(1, '{')
254 ...
241 ...
255 p.end_group(1, '}')
242 p.end_group(1, '}')
256
243
257 The python 2.5 expression would be this:
244 The python 2.5 expression would be this:
258
245
259 with p.group(1, '{', '}'):
246 with p.group(1, '{', '}'):
260 ...
247 ...
261
248
262 The first parameter specifies the indentation for the next line (usually
249 The first parameter specifies the indentation for the next line (usually
263 the width of the opening text), the second the opening text. All
250 the width of the opening text), the second the opening text. All
264 parameters are optional.
251 parameters are optional.
265 """
252 """
266 if open:
253 if open:
267 self.text(open)
254 self.text(open)
268 group = Group(self.group_stack[-1].depth + 1)
255 group = Group(self.group_stack[-1].depth + 1)
269 self.group_stack.append(group)
256 self.group_stack.append(group)
270 self.group_queue.enq(group)
257 self.group_queue.enq(group)
271 self.indentation += indent
258 self.indentation += indent
272
259
273 def end_group(self, dedent=0, close=''):
260 def end_group(self, dedent=0, close=''):
274 """End a group. See `begin_group` for more details."""
261 """End a group. See `begin_group` for more details."""
275 self.indentation -= dedent
262 self.indentation -= dedent
276 group = self.group_stack.pop()
263 group = self.group_stack.pop()
277 if not group.breakables:
264 if not group.breakables:
278 self.group_queue.remove(group)
265 self.group_queue.remove(group)
279 if close:
266 if close:
280 self.text(close)
267 self.text(close)
281
268
282 def flush(self):
269 def flush(self):
283 """Flush data that is left in the buffer."""
270 """Flush data that is left in the buffer."""
284 for data in self.buffer:
271 for data in self.buffer:
285 self.output_width += data.output(self.output, self.output_width)
272 self.output_width += data.output(self.output, self.output_width)
286 self.buffer.clear()
273 self.buffer.clear()
287 self.buffer_width = 0
274 self.buffer_width = 0
288
275
289
276
290 def _get_mro(obj_class):
277 def _get_mro(obj_class):
291 """ Get a reasonable method resolution order of a class and its superclasses
278 """ Get a reasonable method resolution order of a class and its superclasses
292 for both old-style and new-style classes.
279 for both old-style and new-style classes.
293 """
280 """
294 if not hasattr(obj_class, '__mro__'):
281 if not hasattr(obj_class, '__mro__'):
295 # Old-style class. Mix in object to make a fake new-style class.
282 # Old-style class. Mix in object to make a fake new-style class.
296 try:
283 try:
297 obj_class = type(obj_class.__name__, (obj_class, object), {})
284 obj_class = type(obj_class.__name__, (obj_class, object), {})
298 except TypeError:
285 except TypeError:
299 # Old-style extension type that does not descend from object.
286 # Old-style extension type that does not descend from object.
300 # FIXME: try to construct a more thorough MRO.
287 # FIXME: try to construct a more thorough MRO.
301 mro = [obj_class]
288 mro = [obj_class]
302 else:
289 else:
303 mro = obj_class.__mro__[1:-1]
290 mro = obj_class.__mro__[1:-1]
304 else:
291 else:
305 mro = obj_class.__mro__
292 mro = obj_class.__mro__
306 return mro
293 return mro
307
294
308
295
309 class RepresentationPrinter(PrettyPrinter):
296 class RepresentationPrinter(PrettyPrinter):
310 """
297 """
311 Special pretty printer that has a `pretty` method that calls the pretty
298 Special pretty printer that has a `pretty` method that calls the pretty
312 printer for a python object.
299 printer for a python object.
313
300
314 This class stores processing data on `self` so you must *never* use
301 This class stores processing data on `self` so you must *never* use
315 this class in a threaded environment. Always lock it or reinstanciate
302 this class in a threaded environment. Always lock it or reinstanciate
316 it.
303 it.
317
304
318 Instances also have a verbose flag callbacks can access to control their
305 Instances also have a verbose flag callbacks can access to control their
319 output. For example the default instance repr prints all attributes and
306 output. For example the default instance repr prints all attributes and
320 methods that are not prefixed by an underscore if the printer is in
307 methods that are not prefixed by an underscore if the printer is in
321 verbose mode.
308 verbose mode.
322 """
309 """
323
310
324 def __init__(self, output, verbose=False, max_width=79, newline='\n'):
311 def __init__(self, output, verbose=False, max_width=79, newline='\n'):
325 PrettyPrinter.__init__(self, output, max_width, newline)
312 PrettyPrinter.__init__(self, output, max_width, newline)
326 self.verbose = verbose
313 self.verbose = verbose
327 self.stack = []
314 self.stack = []
328
315
329 def pretty(self, obj):
316 def pretty(self, obj):
330 """Pretty print the given object."""
317 """Pretty print the given object."""
331 obj_id = id(obj)
318 obj_id = id(obj)
332 cycle = obj_id in self.stack
319 cycle = obj_id in self.stack
333 self.stack.append(obj_id)
320 self.stack.append(obj_id)
334 self.begin_group()
321 self.begin_group()
335 try:
322 try:
336 obj_class = getattr(obj, '__class__', None) or type(obj)
323 obj_class = getattr(obj, '__class__', None) or type(obj)
337 if hasattr(obj_class, '__pretty__'):
324 if hasattr(obj_class, '__pretty__'):
338 return obj_class.__pretty__(obj, self, cycle)
325 return obj_class.__pretty__(obj, self, cycle)
339 try:
326 try:
340 printer = _singleton_pprinters[obj_id]
327 printer = _singleton_pprinters[obj_id]
341 except (TypeError, KeyError):
328 except (TypeError, KeyError):
342 pass
329 pass
343 else:
330 else:
344 return printer(obj, self, cycle)
331 return printer(obj, self, cycle)
345 for cls in _get_mro(obj_class):
332 for cls in _get_mro(obj_class):
346 if cls in _type_pprinters:
333 if cls in _type_pprinters:
347 return _type_pprinters[cls](obj, self, cycle)
334 return _type_pprinters[cls](obj, self, cycle)
348 else:
335 else:
349 printer = self._in_deferred_types(cls)
336 printer = self._in_deferred_types(cls)
350 if printer is not None:
337 if printer is not None:
351 return printer(obj, self, cycle)
338 return printer(obj, self, cycle)
352 return _default_pprint(obj, self, cycle)
339 return _default_pprint(obj, self, cycle)
353 finally:
340 finally:
354 self.end_group()
341 self.end_group()
355 self.stack.pop()
342 self.stack.pop()
356
343
357 def _in_deferred_types(self, cls):
344 def _in_deferred_types(self, cls):
358 """
345 """
359 Check if the given class is specified in the deferred type registry.
346 Check if the given class is specified in the deferred type registry.
360
347
361 Returns the printer from the registry if it exists, and None if the
348 Returns the printer from the registry if it exists, and None if the
362 class is not in the registry. Successful matches will be moved to the
349 class is not in the registry. Successful matches will be moved to the
363 regular type registry for future use.
350 regular type registry for future use.
364 """
351 """
365 mod = getattr(cls, '__module__', None)
352 mod = getattr(cls, '__module__', None)
366 name = getattr(cls, '__name__', None)
353 name = getattr(cls, '__name__', None)
367 key = (mod, name)
354 key = (mod, name)
368 printer = None
355 printer = None
369 if key in _deferred_type_pprinters:
356 if key in _deferred_type_pprinters:
370 # Move the printer over to the regular registry.
357 # Move the printer over to the regular registry.
371 printer = _deferred_type_pprinters.pop(key)
358 printer = _deferred_type_pprinters.pop(key)
372 _type_pprinters[cls] = printer
359 _type_pprinters[cls] = printer
373 return printer
360 return printer
374
361
375
362
376
363
377 class Printable(object):
364 class Printable(object):
378
365
379 def output(self, stream, output_width):
366 def output(self, stream, output_width):
380 return output_width
367 return output_width
381
368
382
369
383 class Text(Printable):
370 class Text(Printable):
384
371
385 def __init__(self):
372 def __init__(self):
386 self.objs = []
373 self.objs = []
387 self.width = 0
374 self.width = 0
388
375
389 def output(self, stream, output_width):
376 def output(self, stream, output_width):
390 for obj in self.objs:
377 for obj in self.objs:
391 stream.write(obj)
378 stream.write(obj)
392 return output_width + self.width
379 return output_width + self.width
393
380
394 def add(self, obj, width):
381 def add(self, obj, width):
395 self.objs.append(obj)
382 self.objs.append(obj)
396 self.width += width
383 self.width += width
397
384
398
385
399 class Breakable(Printable):
386 class Breakable(Printable):
400
387
401 def __init__(self, seq, width, pretty):
388 def __init__(self, seq, width, pretty):
402 self.obj = seq
389 self.obj = seq
403 self.width = width
390 self.width = width
404 self.pretty = pretty
391 self.pretty = pretty
405 self.indentation = pretty.indentation
392 self.indentation = pretty.indentation
406 self.group = pretty.group_stack[-1]
393 self.group = pretty.group_stack[-1]
407 self.group.breakables.append(self)
394 self.group.breakables.append(self)
408
395
409 def output(self, stream, output_width):
396 def output(self, stream, output_width):
410 self.group.breakables.popleft()
397 self.group.breakables.popleft()
411 if self.group.want_break:
398 if self.group.want_break:
412 stream.write(self.pretty.newline)
399 stream.write(self.pretty.newline)
413 stream.write(' ' * self.indentation)
400 stream.write(' ' * self.indentation)
414 return self.indentation
401 return self.indentation
415 if not self.group.breakables:
402 if not self.group.breakables:
416 self.pretty.group_queue.remove(self.group)
403 self.pretty.group_queue.remove(self.group)
417 stream.write(self.obj)
404 stream.write(self.obj)
418 return output_width + self.width
405 return output_width + self.width
419
406
420
407
421 class Group(Printable):
408 class Group(Printable):
422
409
423 def __init__(self, depth):
410 def __init__(self, depth):
424 self.depth = depth
411 self.depth = depth
425 self.breakables = deque()
412 self.breakables = deque()
426 self.want_break = False
413 self.want_break = False
427
414
428
415
429 class GroupQueue(object):
416 class GroupQueue(object):
430
417
431 def __init__(self, *groups):
418 def __init__(self, *groups):
432 self.queue = []
419 self.queue = []
433 for group in groups:
420 for group in groups:
434 self.enq(group)
421 self.enq(group)
435
422
436 def enq(self, group):
423 def enq(self, group):
437 depth = group.depth
424 depth = group.depth
438 while depth > len(self.queue) - 1:
425 while depth > len(self.queue) - 1:
439 self.queue.append([])
426 self.queue.append([])
440 self.queue[depth].append(group)
427 self.queue[depth].append(group)
441
428
442 def deq(self):
429 def deq(self):
443 for stack in self.queue:
430 for stack in self.queue:
444 for idx, group in enumerate(reversed(stack)):
431 for idx, group in enumerate(reversed(stack)):
445 if group.breakables:
432 if group.breakables:
446 del stack[idx]
433 del stack[idx]
447 group.want_break = True
434 group.want_break = True
448 return group
435 return group
449 for group in stack:
436 for group in stack:
450 group.want_break = True
437 group.want_break = True
451 del stack[:]
438 del stack[:]
452
439
453 def remove(self, group):
440 def remove(self, group):
454 try:
441 try:
455 self.queue[group.depth].remove(group)
442 self.queue[group.depth].remove(group)
456 except ValueError:
443 except ValueError:
457 pass
444 pass
458
445
459
446
460 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
447 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
461
448
462
449
463 def _default_pprint(obj, p, cycle):
450 def _default_pprint(obj, p, cycle):
464 """
451 """
465 The default print function. Used if an object does not provide one and
452 The default print function. Used if an object does not provide one and
466 it's none of the builtin objects.
453 it's none of the builtin objects.
467 """
454 """
468 klass = getattr(obj, '__class__', None) or type(obj)
455 klass = getattr(obj, '__class__', None) or type(obj)
469 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
456 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
470 # A user-provided repr.
457 # A user-provided repr.
471 p.text(repr(obj))
458 p.text(repr(obj))
472 return
459 return
473 p.begin_group(1, '<')
460 p.begin_group(1, '<')
474 p.pretty(klass)
461 p.pretty(klass)
475 p.text(' at 0x%x' % id(obj))
462 p.text(' at 0x%x' % id(obj))
476 if cycle:
463 if cycle:
477 p.text(' ...')
464 p.text(' ...')
478 elif p.verbose:
465 elif p.verbose:
479 first = True
466 first = True
480 for key in dir(obj):
467 for key in dir(obj):
481 if not key.startswith('_'):
468 if not key.startswith('_'):
482 try:
469 try:
483 value = getattr(obj, key)
470 value = getattr(obj, key)
484 except AttributeError:
471 except AttributeError:
485 continue
472 continue
486 if isinstance(value, types.MethodType):
473 if isinstance(value, types.MethodType):
487 continue
474 continue
488 if not first:
475 if not first:
489 p.text(',')
476 p.text(',')
490 p.breakable()
477 p.breakable()
491 p.text(key)
478 p.text(key)
492 p.text('=')
479 p.text('=')
493 step = len(key) + 1
480 step = len(key) + 1
494 p.indentation += step
481 p.indentation += step
495 p.pretty(value)
482 p.pretty(value)
496 p.indentation -= step
483 p.indentation -= step
497 first = False
484 first = False
498 p.end_group(1, '>')
485 p.end_group(1, '>')
499
486
500
487
501 def _seq_pprinter_factory(start, end):
488 def _seq_pprinter_factory(start, end):
502 """
489 """
503 Factory that returns a pprint function useful for sequences. Used by
490 Factory that returns a pprint function useful for sequences. Used by
504 the default pprint for tuples, dicts, lists, sets and frozensets.
491 the default pprint for tuples, dicts, lists, sets and frozensets.
505 """
492 """
506 def inner(obj, p, cycle):
493 def inner(obj, p, cycle):
507 if cycle:
494 if cycle:
508 return p.text(start + '...' + end)
495 return p.text(start + '...' + end)
509 step = len(start)
496 step = len(start)
510 p.begin_group(step, start)
497 p.begin_group(step, start)
511 for idx, x in enumerate(obj):
498 for idx, x in enumerate(obj):
512 if idx:
499 if idx:
513 p.text(',')
500 p.text(',')
514 p.breakable()
501 p.breakable()
515 p.pretty(x)
502 p.pretty(x)
516 if len(obj) == 1 and type(obj) is tuple:
503 if len(obj) == 1 and type(obj) is tuple:
517 # Special case for 1-item tuples.
504 # Special case for 1-item tuples.
518 p.text(',')
505 p.text(',')
519 p.end_group(step, end)
506 p.end_group(step, end)
520 return inner
507 return inner
521
508
522
509
523 def _dict_pprinter_factory(start, end):
510 def _dict_pprinter_factory(start, end):
524 """
511 """
525 Factory that returns a pprint function used by the default pprint of
512 Factory that returns a pprint function used by the default pprint of
526 dicts and dict proxies.
513 dicts and dict proxies.
527 """
514 """
528 def inner(obj, p, cycle):
515 def inner(obj, p, cycle):
529 if cycle:
516 if cycle:
530 return p.text('{...}')
517 return p.text('{...}')
531 p.begin_group(1, start)
518 p.begin_group(1, start)
532 keys = obj.keys()
519 keys = obj.keys()
533 try:
520 try:
534 keys.sort()
521 keys.sort()
535 except Exception, e:
522 except Exception, e:
536 # Sometimes the keys don't sort.
523 # Sometimes the keys don't sort.
537 pass
524 pass
538 for idx, key in enumerate(keys):
525 for idx, key in enumerate(keys):
539 if idx:
526 if idx:
540 p.text(',')
527 p.text(',')
541 p.breakable()
528 p.breakable()
542 p.pretty(key)
529 p.pretty(key)
543 p.text(': ')
530 p.text(': ')
544 p.pretty(obj[key])
531 p.pretty(obj[key])
545 p.end_group(1, end)
532 p.end_group(1, end)
546 return inner
533 return inner
547
534
548
535
549 def _super_pprint(obj, p, cycle):
536 def _super_pprint(obj, p, cycle):
550 """The pprint for the super type."""
537 """The pprint for the super type."""
551 p.begin_group(8, '<super: ')
538 p.begin_group(8, '<super: ')
552 p.pretty(obj.__self_class__)
539 p.pretty(obj.__self_class__)
553 p.text(',')
540 p.text(',')
554 p.breakable()
541 p.breakable()
555 p.pretty(obj.__self__)
542 p.pretty(obj.__self__)
556 p.end_group(8, '>')
543 p.end_group(8, '>')
557
544
558
545
559 def _re_pattern_pprint(obj, p, cycle):
546 def _re_pattern_pprint(obj, p, cycle):
560 """The pprint function for regular expression patterns."""
547 """The pprint function for regular expression patterns."""
561 p.text('re.compile(')
548 p.text('re.compile(')
562 pattern = repr(obj.pattern)
549 pattern = repr(obj.pattern)
563 if pattern[:1] in 'uU':
550 if pattern[:1] in 'uU':
564 pattern = pattern[1:]
551 pattern = pattern[1:]
565 prefix = 'ur'
552 prefix = 'ur'
566 else:
553 else:
567 prefix = 'r'
554 prefix = 'r'
568 pattern = prefix + pattern.replace('\\\\', '\\')
555 pattern = prefix + pattern.replace('\\\\', '\\')
569 p.text(pattern)
556 p.text(pattern)
570 if obj.flags:
557 if obj.flags:
571 p.text(',')
558 p.text(',')
572 p.breakable()
559 p.breakable()
573 done_one = False
560 done_one = False
574 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
561 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
575 'UNICODE', 'VERBOSE', 'DEBUG'):
562 'UNICODE', 'VERBOSE', 'DEBUG'):
576 if obj.flags & getattr(re, flag):
563 if obj.flags & getattr(re, flag):
577 if done_one:
564 if done_one:
578 p.text('|')
565 p.text('|')
579 p.text('re.' + flag)
566 p.text('re.' + flag)
580 done_one = True
567 done_one = True
581 p.text(')')
568 p.text(')')
582
569
583
570
584 def _type_pprint(obj, p, cycle):
571 def _type_pprint(obj, p, cycle):
585 """The pprint for classes and types."""
572 """The pprint for classes and types."""
586 if obj.__module__ in ('__builtin__', 'exceptions'):
573 if obj.__module__ in ('__builtin__', 'exceptions'):
587 name = obj.__name__
574 name = obj.__name__
588 else:
575 else:
589 name = obj.__module__ + '.' + obj.__name__
576 name = obj.__module__ + '.' + obj.__name__
590 p.text(name)
577 p.text(name)
591
578
592
579
593 def _repr_pprint(obj, p, cycle):
580 def _repr_pprint(obj, p, cycle):
594 """A pprint that just redirects to the normal repr function."""
581 """A pprint that just redirects to the normal repr function."""
595 p.text(repr(obj))
582 p.text(repr(obj))
596
583
597
584
598 def _function_pprint(obj, p, cycle):
585 def _function_pprint(obj, p, cycle):
599 """Base pprint for all functions and builtin functions."""
586 """Base pprint for all functions and builtin functions."""
600 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
587 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
601 name = obj.__name__
588 name = obj.__name__
602 else:
589 else:
603 name = obj.__module__ + '.' + obj.__name__
590 name = obj.__module__ + '.' + obj.__name__
604 p.text('<function %s>' % name)
591 p.text('<function %s>' % name)
605
592
606
593
607 def _exception_pprint(obj, p, cycle):
594 def _exception_pprint(obj, p, cycle):
608 """Base pprint for all exceptions."""
595 """Base pprint for all exceptions."""
609 if obj.__class__.__module__ == 'exceptions':
596 if obj.__class__.__module__ == 'exceptions':
610 name = obj.__class__.__name__
597 name = obj.__class__.__name__
611 else:
598 else:
612 name = '%s.%s' % (
599 name = '%s.%s' % (
613 obj.__class__.__module__,
600 obj.__class__.__module__,
614 obj.__class__.__name__
601 obj.__class__.__name__
615 )
602 )
616 step = len(name) + 1
603 step = len(name) + 1
617 p.begin_group(step, '(')
604 p.begin_group(step, '(')
618 for idx, arg in enumerate(getattr(obj, 'args', ())):
605 for idx, arg in enumerate(getattr(obj, 'args', ())):
619 if idx:
606 if idx:
620 p.text(',')
607 p.text(',')
621 p.breakable()
608 p.breakable()
622 p.pretty(arg)
609 p.pretty(arg)
623 p.end_group(step, ')')
610 p.end_group(step, ')')
624
611
625
612
626 #: the exception base
613 #: the exception base
627 try:
614 try:
628 _exception_base = BaseException
615 _exception_base = BaseException
629 except NameError:
616 except NameError:
630 _exception_base = Exception
617 _exception_base = Exception
631
618
632
619
633 #: printers for builtin types
620 #: printers for builtin types
634 _type_pprinters = {
621 _type_pprinters = {
635 int: _repr_pprint,
622 int: _repr_pprint,
636 long: _repr_pprint,
623 long: _repr_pprint,
637 float: _repr_pprint,
624 float: _repr_pprint,
638 str: _repr_pprint,
625 str: _repr_pprint,
639 unicode: _repr_pprint,
626 unicode: _repr_pprint,
640 tuple: _seq_pprinter_factory('(', ')'),
627 tuple: _seq_pprinter_factory('(', ')'),
641 list: _seq_pprinter_factory('[', ']'),
628 list: _seq_pprinter_factory('[', ']'),
642 dict: _dict_pprinter_factory('{', '}'),
629 dict: _dict_pprinter_factory('{', '}'),
643 types.DictProxyType: _dict_pprinter_factory('<dictproxy {', '}>'),
630 types.DictProxyType: _dict_pprinter_factory('<dictproxy {', '}>'),
644 set: _seq_pprinter_factory('set([', '])'),
631 set: _seq_pprinter_factory('set([', '])'),
645 frozenset: _seq_pprinter_factory('frozenset([', '])'),
632 frozenset: _seq_pprinter_factory('frozenset([', '])'),
646 super: _super_pprint,
633 super: _super_pprint,
647 _re_pattern_type: _re_pattern_pprint,
634 _re_pattern_type: _re_pattern_pprint,
648 type: _type_pprint,
635 type: _type_pprint,
649 types.ClassType: _type_pprint,
636 types.ClassType: _type_pprint,
650 types.FunctionType: _function_pprint,
637 types.FunctionType: _function_pprint,
651 types.BuiltinFunctionType: _function_pprint,
638 types.BuiltinFunctionType: _function_pprint,
652 types.SliceType: _repr_pprint,
639 types.SliceType: _repr_pprint,
653 types.MethodType: _repr_pprint,
640 types.MethodType: _repr_pprint,
654 xrange: _repr_pprint,
641 xrange: _repr_pprint,
655 datetime.datetime: _repr_pprint,
642 datetime.datetime: _repr_pprint,
656 datetime.timedelta: _repr_pprint,
643 datetime.timedelta: _repr_pprint,
657 _exception_base: _exception_pprint
644 _exception_base: _exception_pprint
658 }
645 }
659
646
660 #: printers for types specified by name
647 #: printers for types specified by name
661 _deferred_type_pprinters = {
648 _deferred_type_pprinters = {
662 }
649 }
663
650
664 def for_type(typ, func):
651 def for_type(typ, func):
665 """
652 """
666 Add a pretty printer for a given type.
653 Add a pretty printer for a given type.
667 """
654 """
668 oldfunc = _type_pprinters.get(typ, None)
655 oldfunc = _type_pprinters.get(typ, None)
669 if func is not None:
656 if func is not None:
670 # To support easy restoration of old pprinters, we need to ignore Nones.
657 # To support easy restoration of old pprinters, we need to ignore Nones.
671 _type_pprinters[typ] = func
658 _type_pprinters[typ] = func
672 return oldfunc
659 return oldfunc
673
660
674 def for_type_by_name(type_module, type_name, func):
661 def for_type_by_name(type_module, type_name, func):
675 """
662 """
676 Add a pretty printer for a type specified by the module and name of a type
663 Add a pretty printer for a type specified by the module and name of a type
677 rather than the type object itself.
664 rather than the type object itself.
678 """
665 """
679 key = (type_module, type_name)
666 key = (type_module, type_name)
680 oldfunc = _deferred_type_pprinters.get(key, None)
667 oldfunc = _deferred_type_pprinters.get(key, None)
681 if func is not None:
668 if func is not None:
682 # To support easy restoration of old pprinters, we need to ignore Nones.
669 # To support easy restoration of old pprinters, we need to ignore Nones.
683 _deferred_type_pprinters[key] = func
670 _deferred_type_pprinters[key] = func
684 return oldfunc
671 return oldfunc
685
672
686
673
687 #: printers for the default singletons
674 #: printers for the default singletons
688 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
675 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
689 NotImplemented]), _repr_pprint)
676 NotImplemented]), _repr_pprint)
690
677
691
678
692 if __name__ == '__main__':
679 if __name__ == '__main__':
693 from random import randrange
680 from random import randrange
694 class Foo(object):
681 class Foo(object):
695 def __init__(self):
682 def __init__(self):
696 self.foo = 1
683 self.foo = 1
697 self.bar = re.compile(r'\s+')
684 self.bar = re.compile(r'\s+')
698 self.blub = dict.fromkeys(range(30), randrange(1, 40))
685 self.blub = dict.fromkeys(range(30), randrange(1, 40))
699 self.hehe = 23424.234234
686 self.hehe = 23424.234234
700 self.list = ["blub", "blah", self]
687 self.list = ["blub", "blah", self]
701
688
702 def get_foo(self):
689 def get_foo(self):
703 print "foo"
690 print "foo"
704
691
705 pprint(Foo(), verbose=True)
692 pprint(Foo(), verbose=True)
@@ -1,3707 +1,3708 b''
1 # -*- coding: utf-8 -*-
1 # module pyparsing.py
2 # module pyparsing.py
2 #
3 #
3 # Copyright (c) 2003-2009 Paul T. McGuire
4 # Copyright (c) 2003-2009 Paul T. McGuire
4 #
5 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 # the following conditions:
12 #
13 #
13 # The above copyright notice and this permission notice shall be
14 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
15 # included in all copies or substantial portions of the Software.
15 #
16 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #
24 #
24 #from __future__ import generators
25 #from __future__ import generators
25
26
26 __doc__ = \
27 __doc__ = \
27 """
28 """
28 pyparsing module - Classes and methods to define and execute parsing grammars
29 pyparsing module - Classes and methods to define and execute parsing grammars
29
30
30 The pyparsing module is an alternative approach to creating and executing simple grammars,
31 The pyparsing module is an alternative approach to creating and executing simple grammars,
31 vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you
32 vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you
32 don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
33 don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
33 provides a library of classes that you use to construct the grammar directly in Python.
34 provides a library of classes that you use to construct the grammar directly in Python.
34
35
35 Here is a program to parse "Hello, World!" (or any greeting of the form "<salutation>, <addressee>!")::
36 Here is a program to parse "Hello, World!" (or any greeting of the form "<salutation>, <addressee>!")::
36
37
37 from pyparsing import Word, alphas
38 from pyparsing import Word, alphas
38
39
39 # define grammar of a greeting
40 # define grammar of a greeting
40 greet = Word( alphas ) + "," + Word( alphas ) + "!"
41 greet = Word( alphas ) + "," + Word( alphas ) + "!"
41
42
42 hello = "Hello, World!"
43 hello = "Hello, World!"
43 print hello, "->", greet.parseString( hello )
44 print hello, "->", greet.parseString( hello )
44
45
45 The program outputs the following::
46 The program outputs the following::
46
47
47 Hello, World! -> ['Hello', ',', 'World', '!']
48 Hello, World! -> ['Hello', ',', 'World', '!']
48
49
49 The Python representation of the grammar is quite readable, owing to the self-explanatory
50 The Python representation of the grammar is quite readable, owing to the self-explanatory
50 class names, and the use of '+', '|' and '^' operators.
51 class names, and the use of '+', '|' and '^' operators.
51
52
52 The parsed results returned from parseString() can be accessed as a nested list, a dictionary, or an
53 The parsed results returned from parseString() can be accessed as a nested list, a dictionary, or an
53 object with named attributes.
54 object with named attributes.
54
55
55 The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
56 The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
56 - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.)
57 - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.)
57 - quoted strings
58 - quoted strings
58 - embedded comments
59 - embedded comments
59 """
60 """
60
61
61 __version__ = "1.5.2"
62 __version__ = "1.5.2"
62 __versionTime__ = "17 February 2009 19:45"
63 __versionTime__ = "17 February 2009 19:45"
63 __author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
64 __author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
64
65
65 import string
66 import string
66 from weakref import ref as wkref
67 from weakref import ref as wkref
67 import copy
68 import copy
68 import sys
69 import sys
69 import warnings
70 import warnings
70 import re
71 import re
71 import sre_constants
72 import sre_constants
72 #~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
73 #~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
73
74
74 __all__ = [
75 __all__ = [
75 'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
76 'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
76 'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
77 'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
77 'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
78 'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
78 'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
79 'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
79 'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
80 'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
80 'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase',
81 'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase',
81 'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
82 'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
82 'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
83 'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
83 'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
84 'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
84 'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'getTokensEndLoc', 'hexnums',
85 'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'getTokensEndLoc', 'hexnums',
85 'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno',
86 'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno',
86 'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
87 'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
87 'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
88 'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
88 'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity',
89 'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity',
89 'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
90 'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
90 'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
91 'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
91 'indentedBlock', 'originalTextFor',
92 'indentedBlock', 'originalTextFor',
92 ]
93 ]
93
94
94
95
95 """
96 """
96 Detect if we are running version 3.X and make appropriate changes
97 Detect if we are running version 3.X and make appropriate changes
97 Robert A. Clark
98 Robert A. Clark
98 """
99 """
99 if sys.version_info[0] > 2:
100 if sys.version_info[0] > 2:
100 _PY3K = True
101 _PY3K = True
101 _MAX_INT = sys.maxsize
102 _MAX_INT = sys.maxsize
102 basestring = str
103 basestring = str
103 else:
104 else:
104 _PY3K = False
105 _PY3K = False
105 _MAX_INT = sys.maxint
106 _MAX_INT = sys.maxint
106
107
107 if not _PY3K:
108 if not _PY3K:
108 def _ustr(obj):
109 def _ustr(obj):
109 """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
110 """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
110 str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
111 str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
111 then < returns the unicode object | encodes it with the default encoding | ... >.
112 then < returns the unicode object | encodes it with the default encoding | ... >.
112 """
113 """
113 if isinstance(obj,unicode):
114 if isinstance(obj,unicode):
114 return obj
115 return obj
115
116
116 try:
117 try:
117 # If this works, then _ustr(obj) has the same behaviour as str(obj), so
118 # If this works, then _ustr(obj) has the same behaviour as str(obj), so
118 # it won't break any existing code.
119 # it won't break any existing code.
119 return str(obj)
120 return str(obj)
120
121
121 except UnicodeEncodeError:
122 except UnicodeEncodeError:
122 # The Python docs (http://docs.python.org/ref/customization.html#l2h-182)
123 # The Python docs (http://docs.python.org/ref/customization.html#l2h-182)
123 # state that "The return value must be a string object". However, does a
124 # state that "The return value must be a string object". However, does a
124 # unicode object (being a subclass of basestring) count as a "string
125 # unicode object (being a subclass of basestring) count as a "string
125 # object"?
126 # object"?
126 # If so, then return a unicode object:
127 # If so, then return a unicode object:
127 return unicode(obj)
128 return unicode(obj)
128 # Else encode it... but how? There are many choices... :)
129 # Else encode it... but how? There are many choices... :)
129 # Replace unprintables with escape codes?
130 # Replace unprintables with escape codes?
130 #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors')
131 #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors')
131 # Replace unprintables with question marks?
132 # Replace unprintables with question marks?
132 #return unicode(obj).encode(sys.getdefaultencoding(), 'replace')
133 #return unicode(obj).encode(sys.getdefaultencoding(), 'replace')
133 # ...
134 # ...
134 else:
135 else:
135 _ustr = str
136 _ustr = str
136 unichr = chr
137 unichr = chr
137
138
138 if not _PY3K:
139 if not _PY3K:
139 def _str2dict(strg):
140 def _str2dict(strg):
140 return dict( [(c,0) for c in strg] )
141 return dict( [(c,0) for c in strg] )
141 else:
142 else:
142 _str2dict = set
143 _str2dict = set
143
144
144 def _xml_escape(data):
145 def _xml_escape(data):
145 """Escape &, <, >, ", ', etc. in a string of data."""
146 """Escape &, <, >, ", ', etc. in a string of data."""
146
147
147 # ampersand must be replaced first
148 # ampersand must be replaced first
148 from_symbols = '&><"\''
149 from_symbols = '&><"\''
149 to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()]
150 to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()]
150 for from_,to_ in zip(from_symbols, to_symbols):
151 for from_,to_ in zip(from_symbols, to_symbols):
151 data = data.replace(from_, to_)
152 data = data.replace(from_, to_)
152 return data
153 return data
153
154
154 class _Constants(object):
155 class _Constants(object):
155 pass
156 pass
156
157
157 if not _PY3K:
158 if not _PY3K:
158 alphas = string.lowercase + string.uppercase
159 alphas = string.lowercase + string.uppercase
159 else:
160 else:
160 alphas = string.ascii_lowercase + string.ascii_uppercase
161 alphas = string.ascii_lowercase + string.ascii_uppercase
161 nums = string.digits
162 nums = string.digits
162 hexnums = nums + "ABCDEFabcdef"
163 hexnums = nums + "ABCDEFabcdef"
163 alphanums = alphas + nums
164 alphanums = alphas + nums
164 _bslash = chr(92)
165 _bslash = chr(92)
165 printables = "".join( [ c for c in string.printable if c not in string.whitespace ] )
166 printables = "".join( [ c for c in string.printable if c not in string.whitespace ] )
166
167
167 class ParseBaseException(Exception):
168 class ParseBaseException(Exception):
168 """base exception class for all parsing runtime exceptions"""
169 """base exception class for all parsing runtime exceptions"""
169 # Performance tuning: we construct a *lot* of these, so keep this
170 # Performance tuning: we construct a *lot* of these, so keep this
170 # constructor as small and fast as possible
171 # constructor as small and fast as possible
171 def __init__( self, pstr, loc=0, msg=None, elem=None ):
172 def __init__( self, pstr, loc=0, msg=None, elem=None ):
172 self.loc = loc
173 self.loc = loc
173 if msg is None:
174 if msg is None:
174 self.msg = pstr
175 self.msg = pstr
175 self.pstr = ""
176 self.pstr = ""
176 else:
177 else:
177 self.msg = msg
178 self.msg = msg
178 self.pstr = pstr
179 self.pstr = pstr
179 self.parserElement = elem
180 self.parserElement = elem
180
181
181 def __getattr__( self, aname ):
182 def __getattr__( self, aname ):
182 """supported attributes by name are:
183 """supported attributes by name are:
183 - lineno - returns the line number of the exception text
184 - lineno - returns the line number of the exception text
184 - col - returns the column number of the exception text
185 - col - returns the column number of the exception text
185 - line - returns the line containing the exception text
186 - line - returns the line containing the exception text
186 """
187 """
187 if( aname == "lineno" ):
188 if( aname == "lineno" ):
188 return lineno( self.loc, self.pstr )
189 return lineno( self.loc, self.pstr )
189 elif( aname in ("col", "column") ):
190 elif( aname in ("col", "column") ):
190 return col( self.loc, self.pstr )
191 return col( self.loc, self.pstr )
191 elif( aname == "line" ):
192 elif( aname == "line" ):
192 return line( self.loc, self.pstr )
193 return line( self.loc, self.pstr )
193 else:
194 else:
194 raise AttributeError(aname)
195 raise AttributeError(aname)
195
196
196 def __str__( self ):
197 def __str__( self ):
197 return "%s (at char %d), (line:%d, col:%d)" % \
198 return "%s (at char %d), (line:%d, col:%d)" % \
198 ( self.msg, self.loc, self.lineno, self.column )
199 ( self.msg, self.loc, self.lineno, self.column )
199 def __repr__( self ):
200 def __repr__( self ):
200 return _ustr(self)
201 return _ustr(self)
201 def markInputline( self, markerString = ">!<" ):
202 def markInputline( self, markerString = ">!<" ):
202 """Extracts the exception line from the input string, and marks
203 """Extracts the exception line from the input string, and marks
203 the location of the exception with a special symbol.
204 the location of the exception with a special symbol.
204 """
205 """
205 line_str = self.line
206 line_str = self.line
206 line_column = self.column - 1
207 line_column = self.column - 1
207 if markerString:
208 if markerString:
208 line_str = "".join( [line_str[:line_column],
209 line_str = "".join( [line_str[:line_column],
209 markerString, line_str[line_column:]])
210 markerString, line_str[line_column:]])
210 return line_str.strip()
211 return line_str.strip()
211 def __dir__(self):
212 def __dir__(self):
212 return "loc msg pstr parserElement lineno col line " \
213 return "loc msg pstr parserElement lineno col line " \
213 "markInputLine __str__ __repr__".split()
214 "markInputLine __str__ __repr__".split()
214
215
215 class ParseException(ParseBaseException):
216 class ParseException(ParseBaseException):
216 """exception thrown when parse expressions don't match class;
217 """exception thrown when parse expressions don't match class;
217 supported attributes by name are:
218 supported attributes by name are:
218 - lineno - returns the line number of the exception text
219 - lineno - returns the line number of the exception text
219 - col - returns the column number of the exception text
220 - col - returns the column number of the exception text
220 - line - returns the line containing the exception text
221 - line - returns the line containing the exception text
221 """
222 """
222 pass
223 pass
223
224
224 class ParseFatalException(ParseBaseException):
225 class ParseFatalException(ParseBaseException):
225 """user-throwable exception thrown when inconsistent parse content
226 """user-throwable exception thrown when inconsistent parse content
226 is found; stops all parsing immediately"""
227 is found; stops all parsing immediately"""
227 pass
228 pass
228
229
229 class ParseSyntaxException(ParseFatalException):
230 class ParseSyntaxException(ParseFatalException):
230 """just like ParseFatalException, but thrown internally when an
231 """just like ParseFatalException, but thrown internally when an
231 ErrorStop indicates that parsing is to stop immediately because
232 ErrorStop indicates that parsing is to stop immediately because
232 an unbacktrackable syntax error has been found"""
233 an unbacktrackable syntax error has been found"""
233 def __init__(self, pe):
234 def __init__(self, pe):
234 super(ParseSyntaxException, self).__init__(
235 super(ParseSyntaxException, self).__init__(
235 pe.pstr, pe.loc, pe.msg, pe.parserElement)
236 pe.pstr, pe.loc, pe.msg, pe.parserElement)
236
237
237 #~ class ReparseException(ParseBaseException):
238 #~ class ReparseException(ParseBaseException):
238 #~ """Experimental class - parse actions can raise this exception to cause
239 #~ """Experimental class - parse actions can raise this exception to cause
239 #~ pyparsing to reparse the input string:
240 #~ pyparsing to reparse the input string:
240 #~ - with a modified input string, and/or
241 #~ - with a modified input string, and/or
241 #~ - with a modified start location
242 #~ - with a modified start location
242 #~ Set the values of the ReparseException in the constructor, and raise the
243 #~ Set the values of the ReparseException in the constructor, and raise the
243 #~ exception in a parse action to cause pyparsing to use the new string/location.
244 #~ exception in a parse action to cause pyparsing to use the new string/location.
244 #~ Setting the values as None causes no change to be made.
245 #~ Setting the values as None causes no change to be made.
245 #~ """
246 #~ """
246 #~ def __init_( self, newstring, restartLoc ):
247 #~ def __init_( self, newstring, restartLoc ):
247 #~ self.newParseText = newstring
248 #~ self.newParseText = newstring
248 #~ self.reparseLoc = restartLoc
249 #~ self.reparseLoc = restartLoc
249
250
250 class RecursiveGrammarException(Exception):
251 class RecursiveGrammarException(Exception):
251 """exception thrown by validate() if the grammar could be improperly recursive"""
252 """exception thrown by validate() if the grammar could be improperly recursive"""
252 def __init__( self, parseElementList ):
253 def __init__( self, parseElementList ):
253 self.parseElementTrace = parseElementList
254 self.parseElementTrace = parseElementList
254
255
255 def __str__( self ):
256 def __str__( self ):
256 return "RecursiveGrammarException: %s" % self.parseElementTrace
257 return "RecursiveGrammarException: %s" % self.parseElementTrace
257
258
258 class _ParseResultsWithOffset(object):
259 class _ParseResultsWithOffset(object):
259 def __init__(self,p1,p2):
260 def __init__(self,p1,p2):
260 self.tup = (p1,p2)
261 self.tup = (p1,p2)
261 def __getitem__(self,i):
262 def __getitem__(self,i):
262 return self.tup[i]
263 return self.tup[i]
263 def __repr__(self):
264 def __repr__(self):
264 return repr(self.tup)
265 return repr(self.tup)
265 def setOffset(self,i):
266 def setOffset(self,i):
266 self.tup = (self.tup[0],i)
267 self.tup = (self.tup[0],i)
267
268
268 class ParseResults(object):
269 class ParseResults(object):
269 """Structured parse results, to provide multiple means of access to the parsed data:
270 """Structured parse results, to provide multiple means of access to the parsed data:
270 - as a list (len(results))
271 - as a list (len(results))
271 - by list index (results[0], results[1], etc.)
272 - by list index (results[0], results[1], etc.)
272 - by attribute (results.<resultsName>)
273 - by attribute (results.<resultsName>)
273 """
274 """
274 __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" )
275 __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" )
275 def __new__(cls, toklist, name=None, asList=True, modal=True ):
276 def __new__(cls, toklist, name=None, asList=True, modal=True ):
276 if isinstance(toklist, cls):
277 if isinstance(toklist, cls):
277 return toklist
278 return toklist
278 retobj = object.__new__(cls)
279 retobj = object.__new__(cls)
279 retobj.__doinit = True
280 retobj.__doinit = True
280 return retobj
281 return retobj
281
282
282 # Performance tuning: we construct a *lot* of these, so keep this
283 # Performance tuning: we construct a *lot* of these, so keep this
283 # constructor as small and fast as possible
284 # constructor as small and fast as possible
284 def __init__( self, toklist, name=None, asList=True, modal=True ):
285 def __init__( self, toklist, name=None, asList=True, modal=True ):
285 if self.__doinit:
286 if self.__doinit:
286 self.__doinit = False
287 self.__doinit = False
287 self.__name = None
288 self.__name = None
288 self.__parent = None
289 self.__parent = None
289 self.__accumNames = {}
290 self.__accumNames = {}
290 if isinstance(toklist, list):
291 if isinstance(toklist, list):
291 self.__toklist = toklist[:]
292 self.__toklist = toklist[:]
292 else:
293 else:
293 self.__toklist = [toklist]
294 self.__toklist = [toklist]
294 self.__tokdict = dict()
295 self.__tokdict = dict()
295
296
296 if name:
297 if name:
297 if not modal:
298 if not modal:
298 self.__accumNames[name] = 0
299 self.__accumNames[name] = 0
299 if isinstance(name,int):
300 if isinstance(name,int):
300 name = _ustr(name) # will always return a str, but use _ustr for consistency
301 name = _ustr(name) # will always return a str, but use _ustr for consistency
301 self.__name = name
302 self.__name = name
302 if not toklist in (None,'',[]):
303 if not toklist in (None,'',[]):
303 if isinstance(toklist,basestring):
304 if isinstance(toklist,basestring):
304 toklist = [ toklist ]
305 toklist = [ toklist ]
305 if asList:
306 if asList:
306 if isinstance(toklist,ParseResults):
307 if isinstance(toklist,ParseResults):
307 self[name] = _ParseResultsWithOffset(toklist.copy(),0)
308 self[name] = _ParseResultsWithOffset(toklist.copy(),0)
308 else:
309 else:
309 self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
310 self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
310 self[name].__name = name
311 self[name].__name = name
311 else:
312 else:
312 try:
313 try:
313 self[name] = toklist[0]
314 self[name] = toklist[0]
314 except (KeyError,TypeError,IndexError):
315 except (KeyError,TypeError,IndexError):
315 self[name] = toklist
316 self[name] = toklist
316
317
317 def __getitem__( self, i ):
318 def __getitem__( self, i ):
318 if isinstance( i, (int,slice) ):
319 if isinstance( i, (int,slice) ):
319 return self.__toklist[i]
320 return self.__toklist[i]
320 else:
321 else:
321 if i not in self.__accumNames:
322 if i not in self.__accumNames:
322 return self.__tokdict[i][-1][0]
323 return self.__tokdict[i][-1][0]
323 else:
324 else:
324 return ParseResults([ v[0] for v in self.__tokdict[i] ])
325 return ParseResults([ v[0] for v in self.__tokdict[i] ])
325
326
326 def __setitem__( self, k, v ):
327 def __setitem__( self, k, v ):
327 if isinstance(v,_ParseResultsWithOffset):
328 if isinstance(v,_ParseResultsWithOffset):
328 self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
329 self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
329 sub = v[0]
330 sub = v[0]
330 elif isinstance(k,int):
331 elif isinstance(k,int):
331 self.__toklist[k] = v
332 self.__toklist[k] = v
332 sub = v
333 sub = v
333 else:
334 else:
334 self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
335 self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
335 sub = v
336 sub = v
336 if isinstance(sub,ParseResults):
337 if isinstance(sub,ParseResults):
337 sub.__parent = wkref(self)
338 sub.__parent = wkref(self)
338
339
339 def __delitem__( self, i ):
340 def __delitem__( self, i ):
340 if isinstance(i,(int,slice)):
341 if isinstance(i,(int,slice)):
341 mylen = len( self.__toklist )
342 mylen = len( self.__toklist )
342 del self.__toklist[i]
343 del self.__toklist[i]
343
344
344 # convert int to slice
345 # convert int to slice
345 if isinstance(i, int):
346 if isinstance(i, int):
346 if i < 0:
347 if i < 0:
347 i += mylen
348 i += mylen
348 i = slice(i, i+1)
349 i = slice(i, i+1)
349 # get removed indices
350 # get removed indices
350 removed = list(range(*i.indices(mylen)))
351 removed = list(range(*i.indices(mylen)))
351 removed.reverse()
352 removed.reverse()
352 # fixup indices in token dictionary
353 # fixup indices in token dictionary
353 for name in self.__tokdict:
354 for name in self.__tokdict:
354 occurrences = self.__tokdict[name]
355 occurrences = self.__tokdict[name]
355 for j in removed:
356 for j in removed:
356 for k, (value, position) in enumerate(occurrences):
357 for k, (value, position) in enumerate(occurrences):
357 occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
358 occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
358 else:
359 else:
359 del self.__tokdict[i]
360 del self.__tokdict[i]
360
361
361 def __contains__( self, k ):
362 def __contains__( self, k ):
362 return k in self.__tokdict
363 return k in self.__tokdict
363
364
364 def __len__( self ): return len( self.__toklist )
365 def __len__( self ): return len( self.__toklist )
365 def __bool__(self): return len( self.__toklist ) > 0
366 def __bool__(self): return len( self.__toklist ) > 0
366 __nonzero__ = __bool__
367 __nonzero__ = __bool__
367 def __iter__( self ): return iter( self.__toklist )
368 def __iter__( self ): return iter( self.__toklist )
368 def __reversed__( self ): return iter( reversed(self.__toklist) )
369 def __reversed__( self ): return iter( reversed(self.__toklist) )
369 def keys( self ):
370 def keys( self ):
370 """Returns all named result keys."""
371 """Returns all named result keys."""
371 return self.__tokdict.keys()
372 return self.__tokdict.keys()
372
373
373 def pop( self, index=-1 ):
374 def pop( self, index=-1 ):
374 """Removes and returns item at specified index (default=last).
375 """Removes and returns item at specified index (default=last).
375 Will work with either numeric indices or dict-key indicies."""
376 Will work with either numeric indices or dict-key indicies."""
376 ret = self[index]
377 ret = self[index]
377 del self[index]
378 del self[index]
378 return ret
379 return ret
379
380
380 def get(self, key, defaultValue=None):
381 def get(self, key, defaultValue=None):
381 """Returns named result matching the given key, or if there is no
382 """Returns named result matching the given key, or if there is no
382 such name, then returns the given defaultValue or None if no
383 such name, then returns the given defaultValue or None if no
383 defaultValue is specified."""
384 defaultValue is specified."""
384 if key in self:
385 if key in self:
385 return self[key]
386 return self[key]
386 else:
387 else:
387 return defaultValue
388 return defaultValue
388
389
389 def insert( self, index, insStr ):
390 def insert( self, index, insStr ):
390 self.__toklist.insert(index, insStr)
391 self.__toklist.insert(index, insStr)
391 # fixup indices in token dictionary
392 # fixup indices in token dictionary
392 for name in self.__tokdict:
393 for name in self.__tokdict:
393 occurrences = self.__tokdict[name]
394 occurrences = self.__tokdict[name]
394 for k, (value, position) in enumerate(occurrences):
395 for k, (value, position) in enumerate(occurrences):
395 occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
396 occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
396
397
397 def items( self ):
398 def items( self ):
398 """Returns all named result keys and values as a list of tuples."""
399 """Returns all named result keys and values as a list of tuples."""
399 return [(k,self[k]) for k in self.__tokdict]
400 return [(k,self[k]) for k in self.__tokdict]
400
401
401 def values( self ):
402 def values( self ):
402 """Returns all named result values."""
403 """Returns all named result values."""
403 return [ v[-1][0] for v in self.__tokdict.values() ]
404 return [ v[-1][0] for v in self.__tokdict.itervalues() ]
404
405
405 def __getattr__( self, name ):
406 def __getattr__( self, name ):
406 if name not in self.__slots__:
407 if name not in self.__slots__:
407 if name in self.__tokdict:
408 if name in self.__tokdict:
408 if name not in self.__accumNames:
409 if name not in self.__accumNames:
409 return self.__tokdict[name][-1][0]
410 return self.__tokdict[name][-1][0]
410 else:
411 else:
411 return ParseResults([ v[0] for v in self.__tokdict[name] ])
412 return ParseResults([ v[0] for v in self.__tokdict[name] ])
412 else:
413 else:
413 return ""
414 return ""
414 return None
415 return None
415
416
416 def __add__( self, other ):
417 def __add__( self, other ):
417 ret = self.copy()
418 ret = self.copy()
418 ret += other
419 ret += other
419 return ret
420 return ret
420
421
421 def __iadd__( self, other ):
422 def __iadd__( self, other ):
422 if other.__tokdict:
423 if other.__tokdict:
423 offset = len(self.__toklist)
424 offset = len(self.__toklist)
424 addoffset = ( lambda a: (a<0 and offset) or (a+offset) )
425 addoffset = ( lambda a: (a<0 and offset) or (a+offset) )
425 otheritems = other.__tokdict.items()
426 otheritems = other.__tokdict.iteritems()
426 otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
427 otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
427 for (k,vlist) in otheritems for v in vlist]
428 for (k,vlist) in otheritems for v in vlist]
428 for k,v in otherdictitems:
429 for k,v in otherdictitems:
429 self[k] = v
430 self[k] = v
430 if isinstance(v[0],ParseResults):
431 if isinstance(v[0],ParseResults):
431 v[0].__parent = wkref(self)
432 v[0].__parent = wkref(self)
432
433
433 self.__toklist += other.__toklist
434 self.__toklist += other.__toklist
434 self.__accumNames.update( other.__accumNames )
435 self.__accumNames.update( other.__accumNames )
435 del other
436 del other
436 return self
437 return self
437
438
438 def __repr__( self ):
439 def __repr__( self ):
439 return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
440 return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
440
441
441 def __str__( self ):
442 def __str__( self ):
442 out = "["
443 out = "["
443 sep = ""
444 sep = ""
444 for i in self.__toklist:
445 for i in self.__toklist:
445 if isinstance(i, ParseResults):
446 if isinstance(i, ParseResults):
446 out += sep + _ustr(i)
447 out += sep + _ustr(i)
447 else:
448 else:
448 out += sep + repr(i)
449 out += sep + repr(i)
449 sep = ", "
450 sep = ", "
450 out += "]"
451 out += "]"
451 return out
452 return out
452
453
453 def _asStringList( self, sep='' ):
454 def _asStringList( self, sep='' ):
454 out = []
455 out = []
455 for item in self.__toklist:
456 for item in self.__toklist:
456 if out and sep:
457 if out and sep:
457 out.append(sep)
458 out.append(sep)
458 if isinstance( item, ParseResults ):
459 if isinstance( item, ParseResults ):
459 out += item._asStringList()
460 out += item._asStringList()
460 else:
461 else:
461 out.append( _ustr(item) )
462 out.append( _ustr(item) )
462 return out
463 return out
463
464
464 def asList( self ):
465 def asList( self ):
465 """Returns the parse results as a nested list of matching tokens, all converted to strings."""
466 """Returns the parse results as a nested list of matching tokens, all converted to strings."""
466 out = []
467 out = []
467 for res in self.__toklist:
468 for res in self.__toklist:
468 if isinstance(res,ParseResults):
469 if isinstance(res,ParseResults):
469 out.append( res.asList() )
470 out.append( res.asList() )
470 else:
471 else:
471 out.append( res )
472 out.append( res )
472 return out
473 return out
473
474
474 def asDict( self ):
475 def asDict( self ):
475 """Returns the named parse results as dictionary."""
476 """Returns the named parse results as dictionary."""
476 return dict( self.items() )
477 return dict( self.items() )
477
478
478 def copy( self ):
479 def copy( self ):
479 """Returns a new copy of a ParseResults object."""
480 """Returns a new copy of a ParseResults object."""
480 ret = ParseResults( self.__toklist )
481 ret = ParseResults( self.__toklist )
481 ret.__tokdict = self.__tokdict.copy()
482 ret.__tokdict = self.__tokdict.copy()
482 ret.__parent = self.__parent
483 ret.__parent = self.__parent
483 ret.__accumNames.update( self.__accumNames )
484 ret.__accumNames.update( self.__accumNames )
484 ret.__name = self.__name
485 ret.__name = self.__name
485 return ret
486 return ret
486
487
487 def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
488 def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
488 """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names."""
489 """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names."""
489 nl = "\n"
490 nl = "\n"
490 out = []
491 out = []
491 namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items()
492 namedItems = dict([(v[1],k) for (k,vlist) in self.__tokdict.iteritems()
492 for v in vlist ] )
493 for v in vlist ] )
493 nextLevelIndent = indent + " "
494 nextLevelIndent = indent + " "
494
495
495 # collapse out indents if formatting is not desired
496 # collapse out indents if formatting is not desired
496 if not formatted:
497 if not formatted:
497 indent = ""
498 indent = ""
498 nextLevelIndent = ""
499 nextLevelIndent = ""
499 nl = ""
500 nl = ""
500
501
501 selfTag = None
502 selfTag = None
502 if doctag is not None:
503 if doctag is not None:
503 selfTag = doctag
504 selfTag = doctag
504 else:
505 else:
505 if self.__name:
506 if self.__name:
506 selfTag = self.__name
507 selfTag = self.__name
507
508
508 if not selfTag:
509 if not selfTag:
509 if namedItemsOnly:
510 if namedItemsOnly:
510 return ""
511 return ""
511 else:
512 else:
512 selfTag = "ITEM"
513 selfTag = "ITEM"
513
514
514 out += [ nl, indent, "<", selfTag, ">" ]
515 out += [ nl, indent, "<", selfTag, ">" ]
515
516
516 worklist = self.__toklist
517 worklist = self.__toklist
517 for i,res in enumerate(worklist):
518 for i,res in enumerate(worklist):
518 if isinstance(res,ParseResults):
519 if isinstance(res,ParseResults):
519 if i in namedItems:
520 if i in namedItems:
520 out += [ res.asXML(namedItems[i],
521 out += [ res.asXML(namedItems[i],
521 namedItemsOnly and doctag is None,
522 namedItemsOnly and doctag is None,
522 nextLevelIndent,
523 nextLevelIndent,
523 formatted)]
524 formatted)]
524 else:
525 else:
525 out += [ res.asXML(None,
526 out += [ res.asXML(None,
526 namedItemsOnly and doctag is None,
527 namedItemsOnly and doctag is None,
527 nextLevelIndent,
528 nextLevelIndent,
528 formatted)]
529 formatted)]
529 else:
530 else:
530 # individual token, see if there is a name for it
531 # individual token, see if there is a name for it
531 resTag = None
532 resTag = None
532 if i in namedItems:
533 if i in namedItems:
533 resTag = namedItems[i]
534 resTag = namedItems[i]
534 if not resTag:
535 if not resTag:
535 if namedItemsOnly:
536 if namedItemsOnly:
536 continue
537 continue
537 else:
538 else:
538 resTag = "ITEM"
539 resTag = "ITEM"
539 xmlBodyText = _xml_escape(_ustr(res))
540 xmlBodyText = _xml_escape(_ustr(res))
540 out += [ nl, nextLevelIndent, "<", resTag, ">",
541 out += [ nl, nextLevelIndent, "<", resTag, ">",
541 xmlBodyText,
542 xmlBodyText,
542 "</", resTag, ">" ]
543 "</", resTag, ">" ]
543
544
544 out += [ nl, indent, "</", selfTag, ">" ]
545 out += [ nl, indent, "</", selfTag, ">" ]
545 return "".join(out)
546 return "".join(out)
546
547
547 def __lookup(self,sub):
548 def __lookup(self,sub):
548 for k,vlist in self.__tokdict.items():
549 for k,vlist in self.__tokdict.iteritems():
549 for v,loc in vlist:
550 for v,loc in vlist:
550 if sub is v:
551 if sub is v:
551 return k
552 return k
552 return None
553 return None
553
554
554 def getName(self):
555 def getName(self):
555 """Returns the results name for this token expression."""
556 """Returns the results name for this token expression."""
556 if self.__name:
557 if self.__name:
557 return self.__name
558 return self.__name
558 elif self.__parent:
559 elif self.__parent:
559 par = self.__parent()
560 par = self.__parent()
560 if par:
561 if par:
561 return par.__lookup(self)
562 return par.__lookup(self)
562 else:
563 else:
563 return None
564 return None
564 elif (len(self) == 1 and
565 elif (len(self) == 1 and
565 len(self.__tokdict) == 1 and
566 len(self.__tokdict) == 1 and
566 self.__tokdict.values()[0][0][1] in (0,-1)):
567 self.__tokdict.values()[0][0][1] in (0,-1)):
567 return self.__tokdict.keys()[0]
568 return self.__tokdict.keys()[0]
568 else:
569 else:
569 return None
570 return None
570
571
571 def dump(self,indent='',depth=0):
572 def dump(self,indent='',depth=0):
572 """Diagnostic method for listing out the contents of a ParseResults.
573 """Diagnostic method for listing out the contents of a ParseResults.
573 Accepts an optional indent argument so that this string can be embedded
574 Accepts an optional indent argument so that this string can be embedded
574 in a nested display of other data."""
575 in a nested display of other data."""
575 out = []
576 out = []
576 out.append( indent+_ustr(self.asList()) )
577 out.append( indent+_ustr(self.asList()) )
577 keys = self.items()
578 keys = self.items()
578 keys.sort()
579 keys.sort()
579 for k,v in keys:
580 for k,v in keys:
580 if out:
581 if out:
581 out.append('\n')
582 out.append('\n')
582 out.append( "%s%s- %s: " % (indent,(' '*depth), k) )
583 out.append( "%s%s- %s: " % (indent,(' '*depth), k) )
583 if isinstance(v,ParseResults):
584 if isinstance(v,ParseResults):
584 if v.keys():
585 if v.keys():
585 #~ out.append('\n')
586 #~ out.append('\n')
586 out.append( v.dump(indent,depth+1) )
587 out.append( v.dump(indent,depth+1) )
587 #~ out.append('\n')
588 #~ out.append('\n')
588 else:
589 else:
589 out.append(_ustr(v))
590 out.append(_ustr(v))
590 else:
591 else:
591 out.append(_ustr(v))
592 out.append(_ustr(v))
592 #~ out.append('\n')
593 #~ out.append('\n')
593 return "".join(out)
594 return "".join(out)
594
595
595 # add support for pickle protocol
596 # add support for pickle protocol
596 def __getstate__(self):
597 def __getstate__(self):
597 return ( self.__toklist,
598 return ( self.__toklist,
598 ( self.__tokdict.copy(),
599 ( self.__tokdict.copy(),
599 self.__parent is not None and self.__parent() or None,
600 self.__parent is not None and self.__parent() or None,
600 self.__accumNames,
601 self.__accumNames,
601 self.__name ) )
602 self.__name ) )
602
603
603 def __setstate__(self,state):
604 def __setstate__(self,state):
604 self.__toklist = state[0]
605 self.__toklist = state[0]
605 self.__tokdict, \
606 self.__tokdict, \
606 par, \
607 par, \
607 inAccumNames, \
608 inAccumNames, \
608 self.__name = state[1]
609 self.__name = state[1]
609 self.__accumNames = {}
610 self.__accumNames = {}
610 self.__accumNames.update(inAccumNames)
611 self.__accumNames.update(inAccumNames)
611 if par is not None:
612 if par is not None:
612 self.__parent = wkref(par)
613 self.__parent = wkref(par)
613 else:
614 else:
614 self.__parent = None
615 self.__parent = None
615
616
616 def __dir__(self):
617 def __dir__(self):
617 return dir(super(ParseResults,self)) + self.keys()
618 return dir(super(ParseResults,self)) + self.keys()
618
619
619 def col (loc,strg):
620 def col (loc,strg):
620 """Returns current column within a string, counting newlines as line separators.
621 """Returns current column within a string, counting newlines as line separators.
621 The first column is number 1.
622 The first column is number 1.
622
623
623 Note: the default parsing behavior is to expand tabs in the input string
624 Note: the default parsing behavior is to expand tabs in the input string
624 before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
625 before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
625 on parsing strings containing <TAB>s, and suggested methods to maintain a
626 on parsing strings containing <TAB>s, and suggested methods to maintain a
626 consistent view of the parsed string, the parse location, and line and column
627 consistent view of the parsed string, the parse location, and line and column
627 positions within the parsed string.
628 positions within the parsed string.
628 """
629 """
629 return (loc<len(strg) and strg[loc] == '\n') and 1 or loc - strg.rfind("\n", 0, loc)
630 return (loc<len(strg) and strg[loc] == '\n') and 1 or loc - strg.rfind("\n", 0, loc)
630
631
631 def lineno(loc,strg):
632 def lineno(loc,strg):
632 """Returns current line number within a string, counting newlines as line separators.
633 """Returns current line number within a string, counting newlines as line separators.
633 The first line is number 1.
634 The first line is number 1.
634
635
635 Note: the default parsing behavior is to expand tabs in the input string
636 Note: the default parsing behavior is to expand tabs in the input string
636 before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
637 before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
637 on parsing strings containing <TAB>s, and suggested methods to maintain a
638 on parsing strings containing <TAB>s, and suggested methods to maintain a
638 consistent view of the parsed string, the parse location, and line and column
639 consistent view of the parsed string, the parse location, and line and column
639 positions within the parsed string.
640 positions within the parsed string.
640 """
641 """
641 return strg.count("\n",0,loc) + 1
642 return strg.count("\n",0,loc) + 1
642
643
643 def line( loc, strg ):
644 def line( loc, strg ):
644 """Returns the line of text containing loc within a string, counting newlines as line separators.
645 """Returns the line of text containing loc within a string, counting newlines as line separators.
645 """
646 """
646 lastCR = strg.rfind("\n", 0, loc)
647 lastCR = strg.rfind("\n", 0, loc)
647 nextCR = strg.find("\n", loc)
648 nextCR = strg.find("\n", loc)
648 if nextCR > 0:
649 if nextCR > 0:
649 return strg[lastCR+1:nextCR]
650 return strg[lastCR+1:nextCR]
650 else:
651 else:
651 return strg[lastCR+1:]
652 return strg[lastCR+1:]
652
653
653 def _defaultStartDebugAction( instring, loc, expr ):
654 def _defaultStartDebugAction( instring, loc, expr ):
654 print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
655 print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
655
656
656 def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
657 def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
657 print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
658 print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
658
659
659 def _defaultExceptionDebugAction( instring, loc, expr, exc ):
660 def _defaultExceptionDebugAction( instring, loc, expr, exc ):
660 print ("Exception raised:" + _ustr(exc))
661 print ("Exception raised:" + _ustr(exc))
661
662
662 def nullDebugAction(*args):
663 def nullDebugAction(*args):
663 """'Do-nothing' debug action, to suppress debugging output during parsing."""
664 """'Do-nothing' debug action, to suppress debugging output during parsing."""
664 pass
665 pass
665
666
666 class ParserElement(object):
667 class ParserElement(object):
667 """Abstract base level parser element class."""
668 """Abstract base level parser element class."""
668 DEFAULT_WHITE_CHARS = " \n\t\r"
669 DEFAULT_WHITE_CHARS = " \n\t\r"
669
670
670 def setDefaultWhitespaceChars( chars ):
671 def setDefaultWhitespaceChars( chars ):
671 """Overrides the default whitespace chars
672 """Overrides the default whitespace chars
672 """
673 """
673 ParserElement.DEFAULT_WHITE_CHARS = chars
674 ParserElement.DEFAULT_WHITE_CHARS = chars
674 setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars)
675 setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars)
675
676
676 def __init__( self, savelist=False ):
677 def __init__( self, savelist=False ):
677 self.parseAction = list()
678 self.parseAction = list()
678 self.failAction = None
679 self.failAction = None
679 #~ self.name = "<unknown>" # don't define self.name, let subclasses try/except upcall
680 #~ self.name = "<unknown>" # don't define self.name, let subclasses try/except upcall
680 self.strRepr = None
681 self.strRepr = None
681 self.resultsName = None
682 self.resultsName = None
682 self.saveAsList = savelist
683 self.saveAsList = savelist
683 self.skipWhitespace = True
684 self.skipWhitespace = True
684 self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
685 self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
685 self.copyDefaultWhiteChars = True
686 self.copyDefaultWhiteChars = True
686 self.mayReturnEmpty = False # used when checking for left-recursion
687 self.mayReturnEmpty = False # used when checking for left-recursion
687 self.keepTabs = False
688 self.keepTabs = False
688 self.ignoreExprs = list()
689 self.ignoreExprs = list()
689 self.debug = False
690 self.debug = False
690 self.streamlined = False
691 self.streamlined = False
691 self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
692 self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
692 self.errmsg = ""
693 self.errmsg = ""
693 self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
694 self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
694 self.debugActions = ( None, None, None ) #custom debug actions
695 self.debugActions = ( None, None, None ) #custom debug actions
695 self.re = None
696 self.re = None
696 self.callPreparse = True # used to avoid redundant calls to preParse
697 self.callPreparse = True # used to avoid redundant calls to preParse
697 self.callDuringTry = False
698 self.callDuringTry = False
698
699
699 def copy( self ):
700 def copy( self ):
700 """Make a copy of this ParserElement. Useful for defining different parse actions
701 """Make a copy of this ParserElement. Useful for defining different parse actions
701 for the same parsing pattern, using copies of the original parse element."""
702 for the same parsing pattern, using copies of the original parse element."""
702 cpy = copy.copy( self )
703 cpy = copy.copy( self )
703 cpy.parseAction = self.parseAction[:]
704 cpy.parseAction = self.parseAction[:]
704 cpy.ignoreExprs = self.ignoreExprs[:]
705 cpy.ignoreExprs = self.ignoreExprs[:]
705 if self.copyDefaultWhiteChars:
706 if self.copyDefaultWhiteChars:
706 cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
707 cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
707 return cpy
708 return cpy
708
709
709 def setName( self, name ):
710 def setName( self, name ):
710 """Define name for this expression, for use in debugging."""
711 """Define name for this expression, for use in debugging."""
711 self.name = name
712 self.name = name
712 self.errmsg = "Expected " + self.name
713 self.errmsg = "Expected " + self.name
713 if hasattr(self,"exception"):
714 if hasattr(self,"exception"):
714 self.exception.msg = self.errmsg
715 self.exception.msg = self.errmsg
715 return self
716 return self
716
717
717 def setResultsName( self, name, listAllMatches=False ):
718 def setResultsName( self, name, listAllMatches=False ):
718 """Define name for referencing matching tokens as a nested attribute
719 """Define name for referencing matching tokens as a nested attribute
719 of the returned parse results.
720 of the returned parse results.
720 NOTE: this returns a *copy* of the original ParserElement object;
721 NOTE: this returns a *copy* of the original ParserElement object;
721 this is so that the client can define a basic element, such as an
722 this is so that the client can define a basic element, such as an
722 integer, and reference it in multiple places with different names.
723 integer, and reference it in multiple places with different names.
723 """
724 """
724 newself = self.copy()
725 newself = self.copy()
725 newself.resultsName = name
726 newself.resultsName = name
726 newself.modalResults = not listAllMatches
727 newself.modalResults = not listAllMatches
727 return newself
728 return newself
728
729
729 def setBreak(self,breakFlag = True):
730 def setBreak(self,breakFlag = True):
730 """Method to invoke the Python pdb debugger when this element is
731 """Method to invoke the Python pdb debugger when this element is
731 about to be parsed. Set breakFlag to True to enable, False to
732 about to be parsed. Set breakFlag to True to enable, False to
732 disable.
733 disable.
733 """
734 """
734 if breakFlag:
735 if breakFlag:
735 _parseMethod = self._parse
736 _parseMethod = self._parse
736 def breaker(instring, loc, doActions=True, callPreParse=True):
737 def breaker(instring, loc, doActions=True, callPreParse=True):
737 import pdb
738 import pdb
738 pdb.set_trace()
739 pdb.set_trace()
739 return _parseMethod( instring, loc, doActions, callPreParse )
740 return _parseMethod( instring, loc, doActions, callPreParse )
740 breaker._originalParseMethod = _parseMethod
741 breaker._originalParseMethod = _parseMethod
741 self._parse = breaker
742 self._parse = breaker
742 else:
743 else:
743 if hasattr(self._parse,"_originalParseMethod"):
744 if hasattr(self._parse,"_originalParseMethod"):
744 self._parse = self._parse._originalParseMethod
745 self._parse = self._parse._originalParseMethod
745 return self
746 return self
746
747
747 def _normalizeParseActionArgs( f ):
748 def _normalizeParseActionArgs( f ):
748 """Internal method used to decorate parse actions that take fewer than 3 arguments,
749 """Internal method used to decorate parse actions that take fewer than 3 arguments,
749 so that all parse actions can be called as f(s,l,t)."""
750 so that all parse actions can be called as f(s,l,t)."""
750 STAR_ARGS = 4
751 STAR_ARGS = 4
751
752
752 try:
753 try:
753 restore = None
754 restore = None
754 if isinstance(f,type):
755 if isinstance(f,type):
755 restore = f
756 restore = f
756 f = f.__init__
757 f = f.__init__
757 if not _PY3K:
758 if not _PY3K:
758 codeObj = f.func_code
759 codeObj = f.func_code
759 else:
760 else:
760 codeObj = f.code
761 codeObj = f.code
761 if codeObj.co_flags & STAR_ARGS:
762 if codeObj.co_flags & STAR_ARGS:
762 return f
763 return f
763 numargs = codeObj.co_argcount
764 numargs = codeObj.co_argcount
764 if not _PY3K:
765 if not _PY3K:
765 if hasattr(f,"im_self"):
766 if hasattr(f,"im_self"):
766 numargs -= 1
767 numargs -= 1
767 else:
768 else:
768 if hasattr(f,"__self__"):
769 if hasattr(f,"__self__"):
769 numargs -= 1
770 numargs -= 1
770 if restore:
771 if restore:
771 f = restore
772 f = restore
772 except AttributeError:
773 except AttributeError:
773 try:
774 try:
774 if not _PY3K:
775 if not _PY3K:
775 call_im_func_code = f.__call__.im_func.func_code
776 call_im_func_code = f.__call__.im_func.func_code
776 else:
777 else:
777 call_im_func_code = f.__code__
778 call_im_func_code = f.__code__
778
779
779 # not a function, must be a callable object, get info from the
780 # not a function, must be a callable object, get info from the
780 # im_func binding of its bound __call__ method
781 # im_func binding of its bound __call__ method
781 if call_im_func_code.co_flags & STAR_ARGS:
782 if call_im_func_code.co_flags & STAR_ARGS:
782 return f
783 return f
783 numargs = call_im_func_code.co_argcount
784 numargs = call_im_func_code.co_argcount
784 if not _PY3K:
785 if not _PY3K:
785 if hasattr(f.__call__,"im_self"):
786 if hasattr(f.__call__,"im_self"):
786 numargs -= 1
787 numargs -= 1
787 else:
788 else:
788 if hasattr(f.__call__,"__self__"):
789 if hasattr(f.__call__,"__self__"):
789 numargs -= 0
790 numargs -= 0
790 except AttributeError:
791 except AttributeError:
791 if not _PY3K:
792 if not _PY3K:
792 call_func_code = f.__call__.func_code
793 call_func_code = f.__call__.func_code
793 else:
794 else:
794 call_func_code = f.__call__.__code__
795 call_func_code = f.__call__.__code__
795 # not a bound method, get info directly from __call__ method
796 # not a bound method, get info directly from __call__ method
796 if call_func_code.co_flags & STAR_ARGS:
797 if call_func_code.co_flags & STAR_ARGS:
797 return f
798 return f
798 numargs = call_func_code.co_argcount
799 numargs = call_func_code.co_argcount
799 if not _PY3K:
800 if not _PY3K:
800 if hasattr(f.__call__,"im_self"):
801 if hasattr(f.__call__,"im_self"):
801 numargs -= 1
802 numargs -= 1
802 else:
803 else:
803 if hasattr(f.__call__,"__self__"):
804 if hasattr(f.__call__,"__self__"):
804 numargs -= 1
805 numargs -= 1
805
806
806
807
807 #~ print ("adding function %s with %d args" % (f.func_name,numargs))
808 #~ print ("adding function %s with %d args" % (f.func_name,numargs))
808 if numargs == 3:
809 if numargs == 3:
809 return f
810 return f
810 else:
811 else:
811 if numargs > 3:
812 if numargs > 3:
812 def tmp(s,l,t):
813 def tmp(s,l,t):
813 return f(f.__call__.__self__, s,l,t)
814 return f(f.__call__.__self__, s,l,t)
814 if numargs == 2:
815 if numargs == 2:
815 def tmp(s,l,t):
816 def tmp(s,l,t):
816 return f(l,t)
817 return f(l,t)
817 elif numargs == 1:
818 elif numargs == 1:
818 def tmp(s,l,t):
819 def tmp(s,l,t):
819 return f(t)
820 return f(t)
820 else: #~ numargs == 0:
821 else: #~ numargs == 0:
821 def tmp(s,l,t):
822 def tmp(s,l,t):
822 return f()
823 return f()
823 try:
824 try:
824 tmp.__name__ = f.__name__
825 tmp.__name__ = f.__name__
825 except (AttributeError,TypeError):
826 except (AttributeError,TypeError):
826 # no need for special handling if attribute doesnt exist
827 # no need for special handling if attribute doesnt exist
827 pass
828 pass
828 try:
829 try:
829 tmp.__doc__ = f.__doc__
830 tmp.__doc__ = f.__doc__
830 except (AttributeError,TypeError):
831 except (AttributeError,TypeError):
831 # no need for special handling if attribute doesnt exist
832 # no need for special handling if attribute doesnt exist
832 pass
833 pass
833 try:
834 try:
834 tmp.__dict__.update(f.__dict__)
835 tmp.__dict__.update(f.__dict__)
835 except (AttributeError,TypeError):
836 except (AttributeError,TypeError):
836 # no need for special handling if attribute doesnt exist
837 # no need for special handling if attribute doesnt exist
837 pass
838 pass
838 return tmp
839 return tmp
839 _normalizeParseActionArgs = staticmethod(_normalizeParseActionArgs)
840 _normalizeParseActionArgs = staticmethod(_normalizeParseActionArgs)
840
841
841 def setParseAction( self, *fns, **kwargs ):
842 def setParseAction( self, *fns, **kwargs ):
842 """Define action to perform when successfully matching parse element definition.
843 """Define action to perform when successfully matching parse element definition.
843 Parse action fn is a callable method with 0-3 arguments, called as fn(s,loc,toks),
844 Parse action fn is a callable method with 0-3 arguments, called as fn(s,loc,toks),
844 fn(loc,toks), fn(toks), or just fn(), where:
845 fn(loc,toks), fn(toks), or just fn(), where:
845 - s = the original string being parsed (see note below)
846 - s = the original string being parsed (see note below)
846 - loc = the location of the matching substring
847 - loc = the location of the matching substring
847 - toks = a list of the matched tokens, packaged as a ParseResults object
848 - toks = a list of the matched tokens, packaged as a ParseResults object
848 If the functions in fns modify the tokens, they can return them as the return
849 If the functions in fns modify the tokens, they can return them as the return
849 value from fn, and the modified list of tokens will replace the original.
850 value from fn, and the modified list of tokens will replace the original.
850 Otherwise, fn does not need to return any value.
851 Otherwise, fn does not need to return any value.
851
852
852 Note: the default parsing behavior is to expand tabs in the input string
853 Note: the default parsing behavior is to expand tabs in the input string
853 before starting the parsing process. See L{I{parseString}<parseString>} for more information
854 before starting the parsing process. See L{I{parseString}<parseString>} for more information
854 on parsing strings containing <TAB>s, and suggested methods to maintain a
855 on parsing strings containing <TAB>s, and suggested methods to maintain a
855 consistent view of the parsed string, the parse location, and line and column
856 consistent view of the parsed string, the parse location, and line and column
856 positions within the parsed string.
857 positions within the parsed string.
857 """
858 """
858 self.parseAction = list(map(self._normalizeParseActionArgs, list(fns)))
859 self.parseAction = list(map(self._normalizeParseActionArgs, list(fns)))
859 self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"])
860 self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"])
860 return self
861 return self
861
862
862 def addParseAction( self, *fns, **kwargs ):
863 def addParseAction( self, *fns, **kwargs ):
863 """Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}."""
864 """Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}."""
864 self.parseAction += list(map(self._normalizeParseActionArgs, list(fns)))
865 self.parseAction += list(map(self._normalizeParseActionArgs, list(fns)))
865 self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"])
866 self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"])
866 return self
867 return self
867
868
868 def setFailAction( self, fn ):
869 def setFailAction( self, fn ):
869 """Define action to perform if parsing fails at this expression.
870 """Define action to perform if parsing fails at this expression.
870 Fail acton fn is a callable function that takes the arguments
871 Fail acton fn is a callable function that takes the arguments
871 fn(s,loc,expr,err) where:
872 fn(s,loc,expr,err) where:
872 - s = string being parsed
873 - s = string being parsed
873 - loc = location where expression match was attempted and failed
874 - loc = location where expression match was attempted and failed
874 - expr = the parse expression that failed
875 - expr = the parse expression that failed
875 - err = the exception thrown
876 - err = the exception thrown
876 The function returns no value. It may throw ParseFatalException
877 The function returns no value. It may throw ParseFatalException
877 if it is desired to stop parsing immediately."""
878 if it is desired to stop parsing immediately."""
878 self.failAction = fn
879 self.failAction = fn
879 return self
880 return self
880
881
881 def _skipIgnorables( self, instring, loc ):
882 def _skipIgnorables( self, instring, loc ):
882 exprsFound = True
883 exprsFound = True
883 while exprsFound:
884 while exprsFound:
884 exprsFound = False
885 exprsFound = False
885 for e in self.ignoreExprs:
886 for e in self.ignoreExprs:
886 try:
887 try:
887 while 1:
888 while 1:
888 loc,dummy = e._parse( instring, loc )
889 loc,dummy = e._parse( instring, loc )
889 exprsFound = True
890 exprsFound = True
890 except ParseException:
891 except ParseException:
891 pass
892 pass
892 return loc
893 return loc
893
894
894 def preParse( self, instring, loc ):
895 def preParse( self, instring, loc ):
895 if self.ignoreExprs:
896 if self.ignoreExprs:
896 loc = self._skipIgnorables( instring, loc )
897 loc = self._skipIgnorables( instring, loc )
897
898
898 if self.skipWhitespace:
899 if self.skipWhitespace:
899 wt = self.whiteChars
900 wt = self.whiteChars
900 instrlen = len(instring)
901 instrlen = len(instring)
901 while loc < instrlen and instring[loc] in wt:
902 while loc < instrlen and instring[loc] in wt:
902 loc += 1
903 loc += 1
903
904
904 return loc
905 return loc
905
906
906 def parseImpl( self, instring, loc, doActions=True ):
907 def parseImpl( self, instring, loc, doActions=True ):
907 return loc, []
908 return loc, []
908
909
909 def postParse( self, instring, loc, tokenlist ):
910 def postParse( self, instring, loc, tokenlist ):
910 return tokenlist
911 return tokenlist
911
912
912 #~ @profile
913 #~ @profile
913 def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
914 def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
914 debugging = ( self.debug ) #and doActions )
915 debugging = ( self.debug ) #and doActions )
915
916
916 if debugging or self.failAction:
917 if debugging or self.failAction:
917 #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
918 #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
918 if (self.debugActions[0] ):
919 if (self.debugActions[0] ):
919 self.debugActions[0]( instring, loc, self )
920 self.debugActions[0]( instring, loc, self )
920 if callPreParse and self.callPreparse:
921 if callPreParse and self.callPreparse:
921 preloc = self.preParse( instring, loc )
922 preloc = self.preParse( instring, loc )
922 else:
923 else:
923 preloc = loc
924 preloc = loc
924 tokensStart = loc
925 tokensStart = loc
925 try:
926 try:
926 try:
927 try:
927 loc,tokens = self.parseImpl( instring, preloc, doActions )
928 loc,tokens = self.parseImpl( instring, preloc, doActions )
928 except IndexError:
929 except IndexError:
929 raise ParseException( instring, len(instring), self.errmsg, self )
930 raise ParseException( instring, len(instring), self.errmsg, self )
930 except ParseBaseException, err:
931 except ParseBaseException, err:
931 #~ print ("Exception raised:", err)
932 #~ print ("Exception raised:", err)
932 if self.debugActions[2]:
933 if self.debugActions[2]:
933 self.debugActions[2]( instring, tokensStart, self, err )
934 self.debugActions[2]( instring, tokensStart, self, err )
934 if self.failAction:
935 if self.failAction:
935 self.failAction( instring, tokensStart, self, err )
936 self.failAction( instring, tokensStart, self, err )
936 raise
937 raise
937 else:
938 else:
938 if callPreParse and self.callPreparse:
939 if callPreParse and self.callPreparse:
939 preloc = self.preParse( instring, loc )
940 preloc = self.preParse( instring, loc )
940 else:
941 else:
941 preloc = loc
942 preloc = loc
942 tokensStart = loc
943 tokensStart = loc
943 if self.mayIndexError or loc >= len(instring):
944 if self.mayIndexError or loc >= len(instring):
944 try:
945 try:
945 loc,tokens = self.parseImpl( instring, preloc, doActions )
946 loc,tokens = self.parseImpl( instring, preloc, doActions )
946 except IndexError:
947 except IndexError:
947 raise ParseException( instring, len(instring), self.errmsg, self )
948 raise ParseException( instring, len(instring), self.errmsg, self )
948 else:
949 else:
949 loc,tokens = self.parseImpl( instring, preloc, doActions )
950 loc,tokens = self.parseImpl( instring, preloc, doActions )
950
951
951 tokens = self.postParse( instring, loc, tokens )
952 tokens = self.postParse( instring, loc, tokens )
952
953
953 retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
954 retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
954 if self.parseAction and (doActions or self.callDuringTry):
955 if self.parseAction and (doActions or self.callDuringTry):
955 if debugging:
956 if debugging:
956 try:
957 try:
957 for fn in self.parseAction:
958 for fn in self.parseAction:
958 tokens = fn( instring, tokensStart, retTokens )
959 tokens = fn( instring, tokensStart, retTokens )
959 if tokens is not None:
960 if tokens is not None:
960 retTokens = ParseResults( tokens,
961 retTokens = ParseResults( tokens,
961 self.resultsName,
962 self.resultsName,
962 asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
963 asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
963 modal=self.modalResults )
964 modal=self.modalResults )
964 except ParseBaseException, err:
965 except ParseBaseException, err:
965 #~ print "Exception raised in user parse action:", err
966 #~ print "Exception raised in user parse action:", err
966 if (self.debugActions[2] ):
967 if (self.debugActions[2] ):
967 self.debugActions[2]( instring, tokensStart, self, err )
968 self.debugActions[2]( instring, tokensStart, self, err )
968 raise
969 raise
969 else:
970 else:
970 for fn in self.parseAction:
971 for fn in self.parseAction:
971 tokens = fn( instring, tokensStart, retTokens )
972 tokens = fn( instring, tokensStart, retTokens )
972 if tokens is not None:
973 if tokens is not None:
973 retTokens = ParseResults( tokens,
974 retTokens = ParseResults( tokens,
974 self.resultsName,
975 self.resultsName,
975 asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
976 asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
976 modal=self.modalResults )
977 modal=self.modalResults )
977
978
978 if debugging:
979 if debugging:
979 #~ print ("Matched",self,"->",retTokens.asList())
980 #~ print ("Matched",self,"->",retTokens.asList())
980 if (self.debugActions[1] ):
981 if (self.debugActions[1] ):
981 self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
982 self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
982
983
983 return loc, retTokens
984 return loc, retTokens
984
985
985 def tryParse( self, instring, loc ):
986 def tryParse( self, instring, loc ):
986 try:
987 try:
987 return self._parse( instring, loc, doActions=False )[0]
988 return self._parse( instring, loc, doActions=False )[0]
988 except ParseFatalException:
989 except ParseFatalException:
989 raise ParseException( instring, loc, self.errmsg, self)
990 raise ParseException( instring, loc, self.errmsg, self)
990
991
991 # this method gets repeatedly called during backtracking with the same arguments -
992 # this method gets repeatedly called during backtracking with the same arguments -
992 # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
993 # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
993 def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
994 def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
994 lookup = (self,instring,loc,callPreParse,doActions)
995 lookup = (self,instring,loc,callPreParse,doActions)
995 if lookup in ParserElement._exprArgCache:
996 if lookup in ParserElement._exprArgCache:
996 value = ParserElement._exprArgCache[ lookup ]
997 value = ParserElement._exprArgCache[ lookup ]
997 if isinstance(value,Exception):
998 if isinstance(value,Exception):
998 raise value
999 raise value
999 return value
1000 return value
1000 else:
1001 else:
1001 try:
1002 try:
1002 value = self._parseNoCache( instring, loc, doActions, callPreParse )
1003 value = self._parseNoCache( instring, loc, doActions, callPreParse )
1003 ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy())
1004 ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy())
1004 return value
1005 return value
1005 except ParseBaseException, pe:
1006 except ParseBaseException, pe:
1006 ParserElement._exprArgCache[ lookup ] = pe
1007 ParserElement._exprArgCache[ lookup ] = pe
1007 raise
1008 raise
1008
1009
1009 _parse = _parseNoCache
1010 _parse = _parseNoCache
1010
1011
1011 # argument cache for optimizing repeated calls when backtracking through recursive expressions
1012 # argument cache for optimizing repeated calls when backtracking through recursive expressions
1012 _exprArgCache = {}
1013 _exprArgCache = {}
1013 def resetCache():
1014 def resetCache():
1014 ParserElement._exprArgCache.clear()
1015 ParserElement._exprArgCache.clear()
1015 resetCache = staticmethod(resetCache)
1016 resetCache = staticmethod(resetCache)
1016
1017
1017 _packratEnabled = False
1018 _packratEnabled = False
1018 def enablePackrat():
1019 def enablePackrat():
1019 """Enables "packrat" parsing, which adds memoizing to the parsing logic.
1020 """Enables "packrat" parsing, which adds memoizing to the parsing logic.
1020 Repeated parse attempts at the same string location (which happens
1021 Repeated parse attempts at the same string location (which happens
1021 often in many complex grammars) can immediately return a cached value,
1022 often in many complex grammars) can immediately return a cached value,
1022 instead of re-executing parsing/validating code. Memoizing is done of
1023 instead of re-executing parsing/validating code. Memoizing is done of
1023 both valid results and parsing exceptions.
1024 both valid results and parsing exceptions.
1024
1025
1025 This speedup may break existing programs that use parse actions that
1026 This speedup may break existing programs that use parse actions that
1026 have side-effects. For this reason, packrat parsing is disabled when
1027 have side-effects. For this reason, packrat parsing is disabled when
1027 you first import pyparsing. To activate the packrat feature, your
1028 you first import pyparsing. To activate the packrat feature, your
1028 program must call the class method ParserElement.enablePackrat(). If
1029 program must call the class method ParserElement.enablePackrat(). If
1029 your program uses psyco to "compile as you go", you must call
1030 your program uses psyco to "compile as you go", you must call
1030 enablePackrat before calling psyco.full(). If you do not do this,
1031 enablePackrat before calling psyco.full(). If you do not do this,
1031 Python will crash. For best results, call enablePackrat() immediately
1032 Python will crash. For best results, call enablePackrat() immediately
1032 after importing pyparsing.
1033 after importing pyparsing.
1033 """
1034 """
1034 if not ParserElement._packratEnabled:
1035 if not ParserElement._packratEnabled:
1035 ParserElement._packratEnabled = True
1036 ParserElement._packratEnabled = True
1036 ParserElement._parse = ParserElement._parseCache
1037 ParserElement._parse = ParserElement._parseCache
1037 enablePackrat = staticmethod(enablePackrat)
1038 enablePackrat = staticmethod(enablePackrat)
1038
1039
1039 def parseString( self, instring, parseAll=False ):
1040 def parseString( self, instring, parseAll=False ):
1040 """Execute the parse expression with the given string.
1041 """Execute the parse expression with the given string.
1041 This is the main interface to the client code, once the complete
1042 This is the main interface to the client code, once the complete
1042 expression has been built.
1043 expression has been built.
1043
1044
1044 If you want the grammar to require that the entire input string be
1045 If you want the grammar to require that the entire input string be
1045 successfully parsed, then set parseAll to True (equivalent to ending
1046 successfully parsed, then set parseAll to True (equivalent to ending
1046 the grammar with StringEnd()).
1047 the grammar with StringEnd()).
1047
1048
1048 Note: parseString implicitly calls expandtabs() on the input string,
1049 Note: parseString implicitly calls expandtabs() on the input string,
1049 in order to report proper column numbers in parse actions.
1050 in order to report proper column numbers in parse actions.
1050 If the input string contains tabs and
1051 If the input string contains tabs and
1051 the grammar uses parse actions that use the loc argument to index into the
1052 the grammar uses parse actions that use the loc argument to index into the
1052 string being parsed, you can ensure you have a consistent view of the input
1053 string being parsed, you can ensure you have a consistent view of the input
1053 string by:
1054 string by:
1054 - calling parseWithTabs on your grammar before calling parseString
1055 - calling parseWithTabs on your grammar before calling parseString
1055 (see L{I{parseWithTabs}<parseWithTabs>})
1056 (see L{I{parseWithTabs}<parseWithTabs>})
1056 - define your parse action using the full (s,loc,toks) signature, and
1057 - define your parse action using the full (s,loc,toks) signature, and
1057 reference the input string using the parse action's s argument
1058 reference the input string using the parse action's s argument
1058 - explictly expand the tabs in your input string before calling
1059 - explictly expand the tabs in your input string before calling
1059 parseString
1060 parseString
1060 """
1061 """
1061 ParserElement.resetCache()
1062 ParserElement.resetCache()
1062 if not self.streamlined:
1063 if not self.streamlined:
1063 self.streamline()
1064 self.streamline()
1064 #~ self.saveAsList = True
1065 #~ self.saveAsList = True
1065 for e in self.ignoreExprs:
1066 for e in self.ignoreExprs:
1066 e.streamline()
1067 e.streamline()
1067 if not self.keepTabs:
1068 if not self.keepTabs:
1068 instring = instring.expandtabs()
1069 instring = instring.expandtabs()
1069 try:
1070 try:
1070 loc, tokens = self._parse( instring, 0 )
1071 loc, tokens = self._parse( instring, 0 )
1071 if parseAll:
1072 if parseAll:
1072 loc = self.preParse( instring, loc )
1073 loc = self.preParse( instring, loc )
1073 StringEnd()._parse( instring, loc )
1074 StringEnd()._parse( instring, loc )
1074 except ParseBaseException, exc:
1075 except ParseBaseException, exc:
1075 # catch and re-raise exception from here, clears out pyparsing internal stack trace
1076 # catch and re-raise exception from here, clears out pyparsing internal stack trace
1076 raise exc
1077 raise exc
1077 else:
1078 else:
1078 return tokens
1079 return tokens
1079
1080
1080 def scanString( self, instring, maxMatches=_MAX_INT ):
1081 def scanString( self, instring, maxMatches=_MAX_INT ):
1081 """Scan the input string for expression matches. Each match will return the
1082 """Scan the input string for expression matches. Each match will return the
1082 matching tokens, start location, and end location. May be called with optional
1083 matching tokens, start location, and end location. May be called with optional
1083 maxMatches argument, to clip scanning after 'n' matches are found.
1084 maxMatches argument, to clip scanning after 'n' matches are found.
1084
1085
1085 Note that the start and end locations are reported relative to the string
1086 Note that the start and end locations are reported relative to the string
1086 being parsed. See L{I{parseString}<parseString>} for more information on parsing
1087 being parsed. See L{I{parseString}<parseString>} for more information on parsing
1087 strings with embedded tabs."""
1088 strings with embedded tabs."""
1088 if not self.streamlined:
1089 if not self.streamlined:
1089 self.streamline()
1090 self.streamline()
1090 for e in self.ignoreExprs:
1091 for e in self.ignoreExprs:
1091 e.streamline()
1092 e.streamline()
1092
1093
1093 if not self.keepTabs:
1094 if not self.keepTabs:
1094 instring = _ustr(instring).expandtabs()
1095 instring = _ustr(instring).expandtabs()
1095 instrlen = len(instring)
1096 instrlen = len(instring)
1096 loc = 0
1097 loc = 0
1097 preparseFn = self.preParse
1098 preparseFn = self.preParse
1098 parseFn = self._parse
1099 parseFn = self._parse
1099 ParserElement.resetCache()
1100 ParserElement.resetCache()
1100 matches = 0
1101 matches = 0
1101 try:
1102 try:
1102 while loc <= instrlen and matches < maxMatches:
1103 while loc <= instrlen and matches < maxMatches:
1103 try:
1104 try:
1104 preloc = preparseFn( instring, loc )
1105 preloc = preparseFn( instring, loc )
1105 nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
1106 nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
1106 except ParseException:
1107 except ParseException:
1107 loc = preloc+1
1108 loc = preloc+1
1108 else:
1109 else:
1109 matches += 1
1110 matches += 1
1110 yield tokens, preloc, nextLoc
1111 yield tokens, preloc, nextLoc
1111 loc = nextLoc
1112 loc = nextLoc
1112 except ParseBaseException, pe:
1113 except ParseBaseException, pe:
1113 raise pe
1114 raise pe
1114
1115
1115 def transformString( self, instring ):
1116 def transformString( self, instring ):
1116 """Extension to scanString, to modify matching text with modified tokens that may
1117 """Extension to scanString, to modify matching text with modified tokens that may
1117 be returned from a parse action. To use transformString, define a grammar and
1118 be returned from a parse action. To use transformString, define a grammar and
1118 attach a parse action to it that modifies the returned token list.
1119 attach a parse action to it that modifies the returned token list.
1119 Invoking transformString() on a target string will then scan for matches,
1120 Invoking transformString() on a target string will then scan for matches,
1120 and replace the matched text patterns according to the logic in the parse
1121 and replace the matched text patterns according to the logic in the parse
1121 action. transformString() returns the resulting transformed string."""
1122 action. transformString() returns the resulting transformed string."""
1122 out = []
1123 out = []
1123 lastE = 0
1124 lastE = 0
1124 # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
1125 # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
1125 # keep string locs straight between transformString and scanString
1126 # keep string locs straight between transformString and scanString
1126 self.keepTabs = True
1127 self.keepTabs = True
1127 try:
1128 try:
1128 for t,s,e in self.scanString( instring ):
1129 for t,s,e in self.scanString( instring ):
1129 out.append( instring[lastE:s] )
1130 out.append( instring[lastE:s] )
1130 if t:
1131 if t:
1131 if isinstance(t,ParseResults):
1132 if isinstance(t,ParseResults):
1132 out += t.asList()
1133 out += t.asList()
1133 elif isinstance(t,list):
1134 elif isinstance(t,list):
1134 out += t
1135 out += t
1135 else:
1136 else:
1136 out.append(t)
1137 out.append(t)
1137 lastE = e
1138 lastE = e
1138 out.append(instring[lastE:])
1139 out.append(instring[lastE:])
1139 return "".join(map(_ustr,out))
1140 return "".join(map(_ustr,out))
1140 except ParseBaseException, pe:
1141 except ParseBaseException, pe:
1141 raise pe
1142 raise pe
1142
1143
1143 def searchString( self, instring, maxMatches=_MAX_INT ):
1144 def searchString( self, instring, maxMatches=_MAX_INT ):
1144 """Another extension to scanString, simplifying the access to the tokens found
1145 """Another extension to scanString, simplifying the access to the tokens found
1145 to match the given parse expression. May be called with optional
1146 to match the given parse expression. May be called with optional
1146 maxMatches argument, to clip searching after 'n' matches are found.
1147 maxMatches argument, to clip searching after 'n' matches are found.
1147 """
1148 """
1148 try:
1149 try:
1149 return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
1150 return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
1150 except ParseBaseException, pe:
1151 except ParseBaseException, pe:
1151 raise pe
1152 raise pe
1152
1153
1153 def __add__(self, other ):
1154 def __add__(self, other ):
1154 """Implementation of + operator - returns And"""
1155 """Implementation of + operator - returns And"""
1155 if isinstance( other, basestring ):
1156 if isinstance( other, basestring ):
1156 other = Literal( other )
1157 other = Literal( other )
1157 if not isinstance( other, ParserElement ):
1158 if not isinstance( other, ParserElement ):
1158 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1159 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1159 SyntaxWarning, stacklevel=2)
1160 SyntaxWarning, stacklevel=2)
1160 return None
1161 return None
1161 return And( [ self, other ] )
1162 return And( [ self, other ] )
1162
1163
1163 def __radd__(self, other ):
1164 def __radd__(self, other ):
1164 """Implementation of + operator when left operand is not a ParserElement"""
1165 """Implementation of + operator when left operand is not a ParserElement"""
1165 if isinstance( other, basestring ):
1166 if isinstance( other, basestring ):
1166 other = Literal( other )
1167 other = Literal( other )
1167 if not isinstance( other, ParserElement ):
1168 if not isinstance( other, ParserElement ):
1168 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1169 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1169 SyntaxWarning, stacklevel=2)
1170 SyntaxWarning, stacklevel=2)
1170 return None
1171 return None
1171 return other + self
1172 return other + self
1172
1173
1173 def __sub__(self, other):
1174 def __sub__(self, other):
1174 """Implementation of - operator, returns And with error stop"""
1175 """Implementation of - operator, returns And with error stop"""
1175 if isinstance( other, basestring ):
1176 if isinstance( other, basestring ):
1176 other = Literal( other )
1177 other = Literal( other )
1177 if not isinstance( other, ParserElement ):
1178 if not isinstance( other, ParserElement ):
1178 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1179 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1179 SyntaxWarning, stacklevel=2)
1180 SyntaxWarning, stacklevel=2)
1180 return None
1181 return None
1181 return And( [ self, And._ErrorStop(), other ] )
1182 return And( [ self, And._ErrorStop(), other ] )
1182
1183
1183 def __rsub__(self, other ):
1184 def __rsub__(self, other ):
1184 """Implementation of - operator when left operand is not a ParserElement"""
1185 """Implementation of - operator when left operand is not a ParserElement"""
1185 if isinstance( other, basestring ):
1186 if isinstance( other, basestring ):
1186 other = Literal( other )
1187 other = Literal( other )
1187 if not isinstance( other, ParserElement ):
1188 if not isinstance( other, ParserElement ):
1188 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1189 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1189 SyntaxWarning, stacklevel=2)
1190 SyntaxWarning, stacklevel=2)
1190 return None
1191 return None
1191 return other - self
1192 return other - self
1192
1193
1193 def __mul__(self,other):
1194 def __mul__(self,other):
1194 if isinstance(other,int):
1195 if isinstance(other,int):
1195 minElements, optElements = other,0
1196 minElements, optElements = other,0
1196 elif isinstance(other,tuple):
1197 elif isinstance(other,tuple):
1197 other = (other + (None, None))[:2]
1198 other = (other + (None, None))[:2]
1198 if other[0] is None:
1199 if other[0] is None:
1199 other = (0, other[1])
1200 other = (0, other[1])
1200 if isinstance(other[0],int) and other[1] is None:
1201 if isinstance(other[0],int) and other[1] is None:
1201 if other[0] == 0:
1202 if other[0] == 0:
1202 return ZeroOrMore(self)
1203 return ZeroOrMore(self)
1203 if other[0] == 1:
1204 if other[0] == 1:
1204 return OneOrMore(self)
1205 return OneOrMore(self)
1205 else:
1206 else:
1206 return self*other[0] + ZeroOrMore(self)
1207 return self*other[0] + ZeroOrMore(self)
1207 elif isinstance(other[0],int) and isinstance(other[1],int):
1208 elif isinstance(other[0],int) and isinstance(other[1],int):
1208 minElements, optElements = other
1209 minElements, optElements = other
1209 optElements -= minElements
1210 optElements -= minElements
1210 else:
1211 else:
1211 raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
1212 raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
1212 else:
1213 else:
1213 raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
1214 raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
1214
1215
1215 if minElements < 0:
1216 if minElements < 0:
1216 raise ValueError("cannot multiply ParserElement by negative value")
1217 raise ValueError("cannot multiply ParserElement by negative value")
1217 if optElements < 0:
1218 if optElements < 0:
1218 raise ValueError("second tuple value must be greater or equal to first tuple value")
1219 raise ValueError("second tuple value must be greater or equal to first tuple value")
1219 if minElements == optElements == 0:
1220 if minElements == optElements == 0:
1220 raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
1221 raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
1221
1222
1222 if (optElements):
1223 if (optElements):
1223 def makeOptionalList(n):
1224 def makeOptionalList(n):
1224 if n>1:
1225 if n>1:
1225 return Optional(self + makeOptionalList(n-1))
1226 return Optional(self + makeOptionalList(n-1))
1226 else:
1227 else:
1227 return Optional(self)
1228 return Optional(self)
1228 if minElements:
1229 if minElements:
1229 if minElements == 1:
1230 if minElements == 1:
1230 ret = self + makeOptionalList(optElements)
1231 ret = self + makeOptionalList(optElements)
1231 else:
1232 else:
1232 ret = And([self]*minElements) + makeOptionalList(optElements)
1233 ret = And([self]*minElements) + makeOptionalList(optElements)
1233 else:
1234 else:
1234 ret = makeOptionalList(optElements)
1235 ret = makeOptionalList(optElements)
1235 else:
1236 else:
1236 if minElements == 1:
1237 if minElements == 1:
1237 ret = self
1238 ret = self
1238 else:
1239 else:
1239 ret = And([self]*minElements)
1240 ret = And([self]*minElements)
1240 return ret
1241 return ret
1241
1242
1242 def __rmul__(self, other):
1243 def __rmul__(self, other):
1243 return self.__mul__(other)
1244 return self.__mul__(other)
1244
1245
1245 def __or__(self, other ):
1246 def __or__(self, other ):
1246 """Implementation of | operator - returns MatchFirst"""
1247 """Implementation of | operator - returns MatchFirst"""
1247 if isinstance( other, basestring ):
1248 if isinstance( other, basestring ):
1248 other = Literal( other )
1249 other = Literal( other )
1249 if not isinstance( other, ParserElement ):
1250 if not isinstance( other, ParserElement ):
1250 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1251 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1251 SyntaxWarning, stacklevel=2)
1252 SyntaxWarning, stacklevel=2)
1252 return None
1253 return None
1253 return MatchFirst( [ self, other ] )
1254 return MatchFirst( [ self, other ] )
1254
1255
1255 def __ror__(self, other ):
1256 def __ror__(self, other ):
1256 """Implementation of | operator when left operand is not a ParserElement"""
1257 """Implementation of | operator when left operand is not a ParserElement"""
1257 if isinstance( other, basestring ):
1258 if isinstance( other, basestring ):
1258 other = Literal( other )
1259 other = Literal( other )
1259 if not isinstance( other, ParserElement ):
1260 if not isinstance( other, ParserElement ):
1260 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1261 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1261 SyntaxWarning, stacklevel=2)
1262 SyntaxWarning, stacklevel=2)
1262 return None
1263 return None
1263 return other | self
1264 return other | self
1264
1265
1265 def __xor__(self, other ):
1266 def __xor__(self, other ):
1266 """Implementation of ^ operator - returns Or"""
1267 """Implementation of ^ operator - returns Or"""
1267 if isinstance( other, basestring ):
1268 if isinstance( other, basestring ):
1268 other = Literal( other )
1269 other = Literal( other )
1269 if not isinstance( other, ParserElement ):
1270 if not isinstance( other, ParserElement ):
1270 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1271 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1271 SyntaxWarning, stacklevel=2)
1272 SyntaxWarning, stacklevel=2)
1272 return None
1273 return None
1273 return Or( [ self, other ] )
1274 return Or( [ self, other ] )
1274
1275
1275 def __rxor__(self, other ):
1276 def __rxor__(self, other ):
1276 """Implementation of ^ operator when left operand is not a ParserElement"""
1277 """Implementation of ^ operator when left operand is not a ParserElement"""
1277 if isinstance( other, basestring ):
1278 if isinstance( other, basestring ):
1278 other = Literal( other )
1279 other = Literal( other )
1279 if not isinstance( other, ParserElement ):
1280 if not isinstance( other, ParserElement ):
1280 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1281 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1281 SyntaxWarning, stacklevel=2)
1282 SyntaxWarning, stacklevel=2)
1282 return None
1283 return None
1283 return other ^ self
1284 return other ^ self
1284
1285
1285 def __and__(self, other ):
1286 def __and__(self, other ):
1286 """Implementation of & operator - returns Each"""
1287 """Implementation of & operator - returns Each"""
1287 if isinstance( other, basestring ):
1288 if isinstance( other, basestring ):
1288 other = Literal( other )
1289 other = Literal( other )
1289 if not isinstance( other, ParserElement ):
1290 if not isinstance( other, ParserElement ):
1290 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1291 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1291 SyntaxWarning, stacklevel=2)
1292 SyntaxWarning, stacklevel=2)
1292 return None
1293 return None
1293 return Each( [ self, other ] )
1294 return Each( [ self, other ] )
1294
1295
1295 def __rand__(self, other ):
1296 def __rand__(self, other ):
1296 """Implementation of & operator when left operand is not a ParserElement"""
1297 """Implementation of & operator when left operand is not a ParserElement"""
1297 if isinstance( other, basestring ):
1298 if isinstance( other, basestring ):
1298 other = Literal( other )
1299 other = Literal( other )
1299 if not isinstance( other, ParserElement ):
1300 if not isinstance( other, ParserElement ):
1300 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1301 warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
1301 SyntaxWarning, stacklevel=2)
1302 SyntaxWarning, stacklevel=2)
1302 return None
1303 return None
1303 return other & self
1304 return other & self
1304
1305
1305 def __invert__( self ):
1306 def __invert__( self ):
1306 """Implementation of ~ operator - returns NotAny"""
1307 """Implementation of ~ operator - returns NotAny"""
1307 return NotAny( self )
1308 return NotAny( self )
1308
1309
1309 def __call__(self, name):
1310 def __call__(self, name):
1310 """Shortcut for setResultsName, with listAllMatches=default::
1311 """Shortcut for setResultsName, with listAllMatches=default::
1311 userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
1312 userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
1312 could be written as::
1313 could be written as::
1313 userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")
1314 userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")
1314 """
1315 """
1315 return self.setResultsName(name)
1316 return self.setResultsName(name)
1316
1317
1317 def suppress( self ):
1318 def suppress( self ):
1318 """Suppresses the output of this ParserElement; useful to keep punctuation from
1319 """Suppresses the output of this ParserElement; useful to keep punctuation from
1319 cluttering up returned output.
1320 cluttering up returned output.
1320 """
1321 """
1321 return Suppress( self )
1322 return Suppress( self )
1322
1323
1323 def leaveWhitespace( self ):
1324 def leaveWhitespace( self ):
1324 """Disables the skipping of whitespace before matching the characters in the
1325 """Disables the skipping of whitespace before matching the characters in the
1325 ParserElement's defined pattern. This is normally only used internally by
1326 ParserElement's defined pattern. This is normally only used internally by
1326 the pyparsing module, but may be needed in some whitespace-sensitive grammars.
1327 the pyparsing module, but may be needed in some whitespace-sensitive grammars.
1327 """
1328 """
1328 self.skipWhitespace = False
1329 self.skipWhitespace = False
1329 return self
1330 return self
1330
1331
1331 def setWhitespaceChars( self, chars ):
1332 def setWhitespaceChars( self, chars ):
1332 """Overrides the default whitespace chars
1333 """Overrides the default whitespace chars
1333 """
1334 """
1334 self.skipWhitespace = True
1335 self.skipWhitespace = True
1335 self.whiteChars = chars
1336 self.whiteChars = chars
1336 self.copyDefaultWhiteChars = False
1337 self.copyDefaultWhiteChars = False
1337 return self
1338 return self
1338
1339
1339 def parseWithTabs( self ):
1340 def parseWithTabs( self ):
1340 """Overrides default behavior to expand <TAB>s to spaces before parsing the input string.
1341 """Overrides default behavior to expand <TAB>s to spaces before parsing the input string.
1341 Must be called before parseString when the input grammar contains elements that
1342 Must be called before parseString when the input grammar contains elements that
1342 match <TAB> characters."""
1343 match <TAB> characters."""
1343 self.keepTabs = True
1344 self.keepTabs = True
1344 return self
1345 return self
1345
1346
1346 def ignore( self, other ):
1347 def ignore( self, other ):
1347 """Define expression to be ignored (e.g., comments) while doing pattern
1348 """Define expression to be ignored (e.g., comments) while doing pattern
1348 matching; may be called repeatedly, to define multiple comment or other
1349 matching; may be called repeatedly, to define multiple comment or other
1349 ignorable patterns.
1350 ignorable patterns.
1350 """
1351 """
1351 if isinstance( other, Suppress ):
1352 if isinstance( other, Suppress ):
1352 if other not in self.ignoreExprs:
1353 if other not in self.ignoreExprs:
1353 self.ignoreExprs.append( other )
1354 self.ignoreExprs.append( other )
1354 else:
1355 else:
1355 self.ignoreExprs.append( Suppress( other ) )
1356 self.ignoreExprs.append( Suppress( other ) )
1356 return self
1357 return self
1357
1358
1358 def setDebugActions( self, startAction, successAction, exceptionAction ):
1359 def setDebugActions( self, startAction, successAction, exceptionAction ):
1359 """Enable display of debugging messages while doing pattern matching."""
1360 """Enable display of debugging messages while doing pattern matching."""
1360 self.debugActions = (startAction or _defaultStartDebugAction,
1361 self.debugActions = (startAction or _defaultStartDebugAction,
1361 successAction or _defaultSuccessDebugAction,
1362 successAction or _defaultSuccessDebugAction,
1362 exceptionAction or _defaultExceptionDebugAction)
1363 exceptionAction or _defaultExceptionDebugAction)
1363 self.debug = True
1364 self.debug = True
1364 return self
1365 return self
1365
1366
1366 def setDebug( self, flag=True ):
1367 def setDebug( self, flag=True ):
1367 """Enable display of debugging messages while doing pattern matching.
1368 """Enable display of debugging messages while doing pattern matching.
1368 Set flag to True to enable, False to disable."""
1369 Set flag to True to enable, False to disable."""
1369 if flag:
1370 if flag:
1370 self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
1371 self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
1371 else:
1372 else:
1372 self.debug = False
1373 self.debug = False
1373 return self
1374 return self
1374
1375
1375 def __str__( self ):
1376 def __str__( self ):
1376 return self.name
1377 return self.name
1377
1378
1378 def __repr__( self ):
1379 def __repr__( self ):
1379 return _ustr(self)
1380 return _ustr(self)
1380
1381
1381 def streamline( self ):
1382 def streamline( self ):
1382 self.streamlined = True
1383 self.streamlined = True
1383 self.strRepr = None
1384 self.strRepr = None
1384 return self
1385 return self
1385
1386
1386 def checkRecursion( self, parseElementList ):
1387 def checkRecursion( self, parseElementList ):
1387 pass
1388 pass
1388
1389
1389 def validate( self, validateTrace=[] ):
1390 def validate( self, validateTrace=[] ):
1390 """Check defined expressions for valid structure, check for infinite recursive definitions."""
1391 """Check defined expressions for valid structure, check for infinite recursive definitions."""
1391 self.checkRecursion( [] )
1392 self.checkRecursion( [] )
1392
1393
1393 def parseFile( self, file_or_filename, parseAll=False ):
1394 def parseFile( self, file_or_filename, parseAll=False ):
1394 """Execute the parse expression on the given file or filename.
1395 """Execute the parse expression on the given file or filename.
1395 If a filename is specified (instead of a file object),
1396 If a filename is specified (instead of a file object),
1396 the entire file is opened, read, and closed before parsing.
1397 the entire file is opened, read, and closed before parsing.
1397 """
1398 """
1398 try:
1399 try:
1399 file_contents = file_or_filename.read()
1400 file_contents = file_or_filename.read()
1400 except AttributeError:
1401 except AttributeError:
1401 f = open(file_or_filename, "rb")
1402 f = open(file_or_filename, "rb")
1402 file_contents = f.read()
1403 file_contents = f.read()
1403 f.close()
1404 f.close()
1404 try:
1405 try:
1405 return self.parseString(file_contents, parseAll)
1406 return self.parseString(file_contents, parseAll)
1406 except ParseBaseException, exc:
1407 except ParseBaseException, exc:
1407 # catch and re-raise exception from here, clears out pyparsing internal stack trace
1408 # catch and re-raise exception from here, clears out pyparsing internal stack trace
1408 raise exc
1409 raise exc
1409
1410
1410 def getException(self):
1411 def getException(self):
1411 return ParseException("",0,self.errmsg,self)
1412 return ParseException("",0,self.errmsg,self)
1412
1413
1413 def __getattr__(self,aname):
1414 def __getattr__(self,aname):
1414 if aname == "myException":
1415 if aname == "myException":
1415 self.myException = ret = self.getException();
1416 self.myException = ret = self.getException();
1416 return ret;
1417 return ret;
1417 else:
1418 else:
1418 raise AttributeError("no such attribute " + aname)
1419 raise AttributeError("no such attribute " + aname)
1419
1420
1420 def __eq__(self,other):
1421 def __eq__(self,other):
1421 if isinstance(other, ParserElement):
1422 if isinstance(other, ParserElement):
1422 return self is other or self.__dict__ == other.__dict__
1423 return self is other or self.__dict__ == other.__dict__
1423 elif isinstance(other, basestring):
1424 elif isinstance(other, basestring):
1424 try:
1425 try:
1425 self.parseString(_ustr(other), parseAll=True)
1426 self.parseString(_ustr(other), parseAll=True)
1426 return True
1427 return True
1427 except ParseBaseException:
1428 except ParseBaseException:
1428 return False
1429 return False
1429 else:
1430 else:
1430 return super(ParserElement,self)==other
1431 return super(ParserElement,self)==other
1431
1432
1432 def __ne__(self,other):
1433 def __ne__(self,other):
1433 return not (self == other)
1434 return not (self == other)
1434
1435
1435 def __hash__(self):
1436 def __hash__(self):
1436 return hash(id(self))
1437 return hash(id(self))
1437
1438
1438 def __req__(self,other):
1439 def __req__(self,other):
1439 return self == other
1440 return self == other
1440
1441
1441 def __rne__(self,other):
1442 def __rne__(self,other):
1442 return not (self == other)
1443 return not (self == other)
1443
1444
1444
1445
1445 class Token(ParserElement):
1446 class Token(ParserElement):
1446 """Abstract ParserElement subclass, for defining atomic matching patterns."""
1447 """Abstract ParserElement subclass, for defining atomic matching patterns."""
1447 def __init__( self ):
1448 def __init__( self ):
1448 super(Token,self).__init__( savelist=False )
1449 super(Token,self).__init__( savelist=False )
1449 #self.myException = ParseException("",0,"",self)
1450 #self.myException = ParseException("",0,"",self)
1450
1451
1451 def setName(self, name):
1452 def setName(self, name):
1452 s = super(Token,self).setName(name)
1453 s = super(Token,self).setName(name)
1453 self.errmsg = "Expected " + self.name
1454 self.errmsg = "Expected " + self.name
1454 #s.myException.msg = self.errmsg
1455 #s.myException.msg = self.errmsg
1455 return s
1456 return s
1456
1457
1457
1458
1458 class Empty(Token):
1459 class Empty(Token):
1459 """An empty token, will always match."""
1460 """An empty token, will always match."""
1460 def __init__( self ):
1461 def __init__( self ):
1461 super(Empty,self).__init__()
1462 super(Empty,self).__init__()
1462 self.name = "Empty"
1463 self.name = "Empty"
1463 self.mayReturnEmpty = True
1464 self.mayReturnEmpty = True
1464 self.mayIndexError = False
1465 self.mayIndexError = False
1465
1466
1466
1467
1467 class NoMatch(Token):
1468 class NoMatch(Token):
1468 """A token that will never match."""
1469 """A token that will never match."""
1469 def __init__( self ):
1470 def __init__( self ):
1470 super(NoMatch,self).__init__()
1471 super(NoMatch,self).__init__()
1471 self.name = "NoMatch"
1472 self.name = "NoMatch"
1472 self.mayReturnEmpty = True
1473 self.mayReturnEmpty = True
1473 self.mayIndexError = False
1474 self.mayIndexError = False
1474 self.errmsg = "Unmatchable token"
1475 self.errmsg = "Unmatchable token"
1475 #self.myException.msg = self.errmsg
1476 #self.myException.msg = self.errmsg
1476
1477
1477 def parseImpl( self, instring, loc, doActions=True ):
1478 def parseImpl( self, instring, loc, doActions=True ):
1478 exc = self.myException
1479 exc = self.myException
1479 exc.loc = loc
1480 exc.loc = loc
1480 exc.pstr = instring
1481 exc.pstr = instring
1481 raise exc
1482 raise exc
1482
1483
1483
1484
1484 class Literal(Token):
1485 class Literal(Token):
1485 """Token to exactly match a specified string."""
1486 """Token to exactly match a specified string."""
1486 def __init__( self, matchString ):
1487 def __init__( self, matchString ):
1487 super(Literal,self).__init__()
1488 super(Literal,self).__init__()
1488 self.match = matchString
1489 self.match = matchString
1489 self.matchLen = len(matchString)
1490 self.matchLen = len(matchString)
1490 try:
1491 try:
1491 self.firstMatchChar = matchString[0]
1492 self.firstMatchChar = matchString[0]
1492 except IndexError:
1493 except IndexError:
1493 warnings.warn("null string passed to Literal; use Empty() instead",
1494 warnings.warn("null string passed to Literal; use Empty() instead",
1494 SyntaxWarning, stacklevel=2)
1495 SyntaxWarning, stacklevel=2)
1495 self.__class__ = Empty
1496 self.__class__ = Empty
1496 self.name = '"%s"' % _ustr(self.match)
1497 self.name = '"%s"' % _ustr(self.match)
1497 self.errmsg = "Expected " + self.name
1498 self.errmsg = "Expected " + self.name
1498 self.mayReturnEmpty = False
1499 self.mayReturnEmpty = False
1499 #self.myException.msg = self.errmsg
1500 #self.myException.msg = self.errmsg
1500 self.mayIndexError = False
1501 self.mayIndexError = False
1501
1502
1502 # Performance tuning: this routine gets called a *lot*
1503 # Performance tuning: this routine gets called a *lot*
1503 # if this is a single character match string and the first character matches,
1504 # if this is a single character match string and the first character matches,
1504 # short-circuit as quickly as possible, and avoid calling startswith
1505 # short-circuit as quickly as possible, and avoid calling startswith
1505 #~ @profile
1506 #~ @profile
1506 def parseImpl( self, instring, loc, doActions=True ):
1507 def parseImpl( self, instring, loc, doActions=True ):
1507 if (instring[loc] == self.firstMatchChar and
1508 if (instring[loc] == self.firstMatchChar and
1508 (self.matchLen==1 or instring.startswith(self.match,loc)) ):
1509 (self.matchLen==1 or instring.startswith(self.match,loc)) ):
1509 return loc+self.matchLen, self.match
1510 return loc+self.matchLen, self.match
1510 #~ raise ParseException( instring, loc, self.errmsg )
1511 #~ raise ParseException( instring, loc, self.errmsg )
1511 exc = self.myException
1512 exc = self.myException
1512 exc.loc = loc
1513 exc.loc = loc
1513 exc.pstr = instring
1514 exc.pstr = instring
1514 raise exc
1515 raise exc
1515 _L = Literal
1516 _L = Literal
1516
1517
1517 class Keyword(Token):
1518 class Keyword(Token):
1518 """Token to exactly match a specified string as a keyword, that is, it must be
1519 """Token to exactly match a specified string as a keyword, that is, it must be
1519 immediately followed by a non-keyword character. Compare with Literal::
1520 immediately followed by a non-keyword character. Compare with Literal::
1520 Literal("if") will match the leading 'if' in 'ifAndOnlyIf'.
1521 Literal("if") will match the leading 'if' in 'ifAndOnlyIf'.
1521 Keyword("if") will not; it will only match the leading 'if in 'if x=1', or 'if(y==2)'
1522 Keyword("if") will not; it will only match the leading 'if in 'if x=1', or 'if(y==2)'
1522 Accepts two optional constructor arguments in addition to the keyword string:
1523 Accepts two optional constructor arguments in addition to the keyword string:
1523 identChars is a string of characters that would be valid identifier characters,
1524 identChars is a string of characters that would be valid identifier characters,
1524 defaulting to all alphanumerics + "_" and "$"; caseless allows case-insensitive
1525 defaulting to all alphanumerics + "_" and "$"; caseless allows case-insensitive
1525 matching, default is False.
1526 matching, default is False.
1526 """
1527 """
1527 DEFAULT_KEYWORD_CHARS = alphanums+"_$"
1528 DEFAULT_KEYWORD_CHARS = alphanums+"_$"
1528
1529
1529 def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ):
1530 def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ):
1530 super(Keyword,self).__init__()
1531 super(Keyword,self).__init__()
1531 self.match = matchString
1532 self.match = matchString
1532 self.matchLen = len(matchString)
1533 self.matchLen = len(matchString)
1533 try:
1534 try:
1534 self.firstMatchChar = matchString[0]
1535 self.firstMatchChar = matchString[0]
1535 except IndexError:
1536 except IndexError:
1536 warnings.warn("null string passed to Keyword; use Empty() instead",
1537 warnings.warn("null string passed to Keyword; use Empty() instead",
1537 SyntaxWarning, stacklevel=2)
1538 SyntaxWarning, stacklevel=2)
1538 self.name = '"%s"' % self.match
1539 self.name = '"%s"' % self.match
1539 self.errmsg = "Expected " + self.name
1540 self.errmsg = "Expected " + self.name
1540 self.mayReturnEmpty = False
1541 self.mayReturnEmpty = False
1541 #self.myException.msg = self.errmsg
1542 #self.myException.msg = self.errmsg
1542 self.mayIndexError = False
1543 self.mayIndexError = False
1543 self.caseless = caseless
1544 self.caseless = caseless
1544 if caseless:
1545 if caseless:
1545 self.caselessmatch = matchString.upper()
1546 self.caselessmatch = matchString.upper()
1546 identChars = identChars.upper()
1547 identChars = identChars.upper()
1547 self.identChars = _str2dict(identChars)
1548 self.identChars = _str2dict(identChars)
1548
1549
1549 def parseImpl( self, instring, loc, doActions=True ):
1550 def parseImpl( self, instring, loc, doActions=True ):
1550 if self.caseless:
1551 if self.caseless:
1551 if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
1552 if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
1552 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
1553 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
1553 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
1554 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
1554 return loc+self.matchLen, self.match
1555 return loc+self.matchLen, self.match
1555 else:
1556 else:
1556 if (instring[loc] == self.firstMatchChar and
1557 if (instring[loc] == self.firstMatchChar and
1557 (self.matchLen==1 or instring.startswith(self.match,loc)) and
1558 (self.matchLen==1 or instring.startswith(self.match,loc)) and
1558 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
1559 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
1559 (loc == 0 or instring[loc-1] not in self.identChars) ):
1560 (loc == 0 or instring[loc-1] not in self.identChars) ):
1560 return loc+self.matchLen, self.match
1561 return loc+self.matchLen, self.match
1561 #~ raise ParseException( instring, loc, self.errmsg )
1562 #~ raise ParseException( instring, loc, self.errmsg )
1562 exc = self.myException
1563 exc = self.myException
1563 exc.loc = loc
1564 exc.loc = loc
1564 exc.pstr = instring
1565 exc.pstr = instring
1565 raise exc
1566 raise exc
1566
1567
1567 def copy(self):
1568 def copy(self):
1568 c = super(Keyword,self).copy()
1569 c = super(Keyword,self).copy()
1569 c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
1570 c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
1570 return c
1571 return c
1571
1572
1572 def setDefaultKeywordChars( chars ):
1573 def setDefaultKeywordChars( chars ):
1573 """Overrides the default Keyword chars
1574 """Overrides the default Keyword chars
1574 """
1575 """
1575 Keyword.DEFAULT_KEYWORD_CHARS = chars
1576 Keyword.DEFAULT_KEYWORD_CHARS = chars
1576 setDefaultKeywordChars = staticmethod(setDefaultKeywordChars)
1577 setDefaultKeywordChars = staticmethod(setDefaultKeywordChars)
1577
1578
1578 class CaselessLiteral(Literal):
1579 class CaselessLiteral(Literal):
1579 """Token to match a specified string, ignoring case of letters.
1580 """Token to match a specified string, ignoring case of letters.
1580 Note: the matched results will always be in the case of the given
1581 Note: the matched results will always be in the case of the given
1581 match string, NOT the case of the input text.
1582 match string, NOT the case of the input text.
1582 """
1583 """
1583 def __init__( self, matchString ):
1584 def __init__( self, matchString ):
1584 super(CaselessLiteral,self).__init__( matchString.upper() )
1585 super(CaselessLiteral,self).__init__( matchString.upper() )
1585 # Preserve the defining literal.
1586 # Preserve the defining literal.
1586 self.returnString = matchString
1587 self.returnString = matchString
1587 self.name = "'%s'" % self.returnString
1588 self.name = "'%s'" % self.returnString
1588 self.errmsg = "Expected " + self.name
1589 self.errmsg = "Expected " + self.name
1589 #self.myException.msg = self.errmsg
1590 #self.myException.msg = self.errmsg
1590
1591
1591 def parseImpl( self, instring, loc, doActions=True ):
1592 def parseImpl( self, instring, loc, doActions=True ):
1592 if instring[ loc:loc+self.matchLen ].upper() == self.match:
1593 if instring[ loc:loc+self.matchLen ].upper() == self.match:
1593 return loc+self.matchLen, self.returnString
1594 return loc+self.matchLen, self.returnString
1594 #~ raise ParseException( instring, loc, self.errmsg )
1595 #~ raise ParseException( instring, loc, self.errmsg )
1595 exc = self.myException
1596 exc = self.myException
1596 exc.loc = loc
1597 exc.loc = loc
1597 exc.pstr = instring
1598 exc.pstr = instring
1598 raise exc
1599 raise exc
1599
1600
1600 class CaselessKeyword(Keyword):
1601 class CaselessKeyword(Keyword):
1601 def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ):
1602 def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ):
1602 super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
1603 super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
1603
1604
1604 def parseImpl( self, instring, loc, doActions=True ):
1605 def parseImpl( self, instring, loc, doActions=True ):
1605 if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
1606 if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
1606 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
1607 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
1607 return loc+self.matchLen, self.match
1608 return loc+self.matchLen, self.match
1608 #~ raise ParseException( instring, loc, self.errmsg )
1609 #~ raise ParseException( instring, loc, self.errmsg )
1609 exc = self.myException
1610 exc = self.myException
1610 exc.loc = loc
1611 exc.loc = loc
1611 exc.pstr = instring
1612 exc.pstr = instring
1612 raise exc
1613 raise exc
1613
1614
1614 class Word(Token):
1615 class Word(Token):
1615 """Token for matching words composed of allowed character sets.
1616 """Token for matching words composed of allowed character sets.
1616 Defined with string containing all allowed initial characters,
1617 Defined with string containing all allowed initial characters,
1617 an optional string containing allowed body characters (if omitted,
1618 an optional string containing allowed body characters (if omitted,
1618 defaults to the initial character set), and an optional minimum,
1619 defaults to the initial character set), and an optional minimum,
1619 maximum, and/or exact length. The default value for min is 1 (a
1620 maximum, and/or exact length. The default value for min is 1 (a
1620 minimum value < 1 is not valid); the default values for max and exact
1621 minimum value < 1 is not valid); the default values for max and exact
1621 are 0, meaning no maximum or exact length restriction.
1622 are 0, meaning no maximum or exact length restriction.
1622 """
1623 """
1623 def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False ):
1624 def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False ):
1624 super(Word,self).__init__()
1625 super(Word,self).__init__()
1625 self.initCharsOrig = initChars
1626 self.initCharsOrig = initChars
1626 self.initChars = _str2dict(initChars)
1627 self.initChars = _str2dict(initChars)
1627 if bodyChars :
1628 if bodyChars :
1628 self.bodyCharsOrig = bodyChars
1629 self.bodyCharsOrig = bodyChars
1629 self.bodyChars = _str2dict(bodyChars)
1630 self.bodyChars = _str2dict(bodyChars)
1630 else:
1631 else:
1631 self.bodyCharsOrig = initChars
1632 self.bodyCharsOrig = initChars
1632 self.bodyChars = _str2dict(initChars)
1633 self.bodyChars = _str2dict(initChars)
1633
1634
1634 self.maxSpecified = max > 0
1635 self.maxSpecified = max > 0
1635
1636
1636 if min < 1:
1637 if min < 1:
1637 raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
1638 raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
1638
1639
1639 self.minLen = min
1640 self.minLen = min
1640
1641
1641 if max > 0:
1642 if max > 0:
1642 self.maxLen = max
1643 self.maxLen = max
1643 else:
1644 else:
1644 self.maxLen = _MAX_INT
1645 self.maxLen = _MAX_INT
1645
1646
1646 if exact > 0:
1647 if exact > 0:
1647 self.maxLen = exact
1648 self.maxLen = exact
1648 self.minLen = exact
1649 self.minLen = exact
1649
1650
1650 self.name = _ustr(self)
1651 self.name = _ustr(self)
1651 self.errmsg = "Expected " + self.name
1652 self.errmsg = "Expected " + self.name
1652 #self.myException.msg = self.errmsg
1653 #self.myException.msg = self.errmsg
1653 self.mayIndexError = False
1654 self.mayIndexError = False
1654 self.asKeyword = asKeyword
1655 self.asKeyword = asKeyword
1655
1656
1656 if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
1657 if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
1657 if self.bodyCharsOrig == self.initCharsOrig:
1658 if self.bodyCharsOrig == self.initCharsOrig:
1658 self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
1659 self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
1659 elif len(self.bodyCharsOrig) == 1:
1660 elif len(self.bodyCharsOrig) == 1:
1660 self.reString = "%s[%s]*" % \
1661 self.reString = "%s[%s]*" % \
1661 (re.escape(self.initCharsOrig),
1662 (re.escape(self.initCharsOrig),
1662 _escapeRegexRangeChars(self.bodyCharsOrig),)
1663 _escapeRegexRangeChars(self.bodyCharsOrig),)
1663 else:
1664 else:
1664 self.reString = "[%s][%s]*" % \
1665 self.reString = "[%s][%s]*" % \
1665 (_escapeRegexRangeChars(self.initCharsOrig),
1666 (_escapeRegexRangeChars(self.initCharsOrig),
1666 _escapeRegexRangeChars(self.bodyCharsOrig),)
1667 _escapeRegexRangeChars(self.bodyCharsOrig),)
1667 if self.asKeyword:
1668 if self.asKeyword:
1668 self.reString = r"\b"+self.reString+r"\b"
1669 self.reString = r"\b"+self.reString+r"\b"
1669 try:
1670 try:
1670 self.re = re.compile( self.reString )
1671 self.re = re.compile( self.reString )
1671 except:
1672 except:
1672 self.re = None
1673 self.re = None
1673
1674
1674 def parseImpl( self, instring, loc, doActions=True ):
1675 def parseImpl( self, instring, loc, doActions=True ):
1675 if self.re:
1676 if self.re:
1676 result = self.re.match(instring,loc)
1677 result = self.re.match(instring,loc)
1677 if not result:
1678 if not result:
1678 exc = self.myException
1679 exc = self.myException
1679 exc.loc = loc
1680 exc.loc = loc
1680 exc.pstr = instring
1681 exc.pstr = instring
1681 raise exc
1682 raise exc
1682
1683
1683 loc = result.end()
1684 loc = result.end()
1684 return loc,result.group()
1685 return loc,result.group()
1685
1686
1686 if not(instring[ loc ] in self.initChars):
1687 if not(instring[ loc ] in self.initChars):
1687 #~ raise ParseException( instring, loc, self.errmsg )
1688 #~ raise ParseException( instring, loc, self.errmsg )
1688 exc = self.myException
1689 exc = self.myException
1689 exc.loc = loc
1690 exc.loc = loc
1690 exc.pstr = instring
1691 exc.pstr = instring
1691 raise exc
1692 raise exc
1692 start = loc
1693 start = loc
1693 loc += 1
1694 loc += 1
1694 instrlen = len(instring)
1695 instrlen = len(instring)
1695 bodychars = self.bodyChars
1696 bodychars = self.bodyChars
1696 maxloc = start + self.maxLen
1697 maxloc = start + self.maxLen
1697 maxloc = min( maxloc, instrlen )
1698 maxloc = min( maxloc, instrlen )
1698 while loc < maxloc and instring[loc] in bodychars:
1699 while loc < maxloc and instring[loc] in bodychars:
1699 loc += 1
1700 loc += 1
1700
1701
1701 throwException = False
1702 throwException = False
1702 if loc - start < self.minLen:
1703 if loc - start < self.minLen:
1703 throwException = True
1704 throwException = True
1704 if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
1705 if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
1705 throwException = True
1706 throwException = True
1706 if self.asKeyword:
1707 if self.asKeyword:
1707 if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars):
1708 if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars):
1708 throwException = True
1709 throwException = True
1709
1710
1710 if throwException:
1711 if throwException:
1711 #~ raise ParseException( instring, loc, self.errmsg )
1712 #~ raise ParseException( instring, loc, self.errmsg )
1712 exc = self.myException
1713 exc = self.myException
1713 exc.loc = loc
1714 exc.loc = loc
1714 exc.pstr = instring
1715 exc.pstr = instring
1715 raise exc
1716 raise exc
1716
1717
1717 return loc, instring[start:loc]
1718 return loc, instring[start:loc]
1718
1719
1719 def __str__( self ):
1720 def __str__( self ):
1720 try:
1721 try:
1721 return super(Word,self).__str__()
1722 return super(Word,self).__str__()
1722 except:
1723 except:
1723 pass
1724 pass
1724
1725
1725
1726
1726 if self.strRepr is None:
1727 if self.strRepr is None:
1727
1728
1728 def charsAsStr(s):
1729 def charsAsStr(s):
1729 if len(s)>4:
1730 if len(s)>4:
1730 return s[:4]+"..."
1731 return s[:4]+"..."
1731 else:
1732 else:
1732 return s
1733 return s
1733
1734
1734 if ( self.initCharsOrig != self.bodyCharsOrig ):
1735 if ( self.initCharsOrig != self.bodyCharsOrig ):
1735 self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
1736 self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
1736 else:
1737 else:
1737 self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
1738 self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
1738
1739
1739 return self.strRepr
1740 return self.strRepr
1740
1741
1741
1742
1742 class Regex(Token):
1743 class Regex(Token):
1743 """Token for matching strings that match a given regular expression.
1744 """Token for matching strings that match a given regular expression.
1744 Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
1745 Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
1745 """
1746 """
1746 def __init__( self, pattern, flags=0):
1747 def __init__( self, pattern, flags=0):
1747 """The parameters pattern and flags are passed to the re.compile() function as-is. See the Python re module for an explanation of the acceptable patterns and flags."""
1748 """The parameters pattern and flags are passed to the re.compile() function as-is. See the Python re module for an explanation of the acceptable patterns and flags."""
1748 super(Regex,self).__init__()
1749 super(Regex,self).__init__()
1749
1750
1750 if len(pattern) == 0:
1751 if len(pattern) == 0:
1751 warnings.warn("null string passed to Regex; use Empty() instead",
1752 warnings.warn("null string passed to Regex; use Empty() instead",
1752 SyntaxWarning, stacklevel=2)
1753 SyntaxWarning, stacklevel=2)
1753
1754
1754 self.pattern = pattern
1755 self.pattern = pattern
1755 self.flags = flags
1756 self.flags = flags
1756
1757
1757 try:
1758 try:
1758 self.re = re.compile(self.pattern, self.flags)
1759 self.re = re.compile(self.pattern, self.flags)
1759 self.reString = self.pattern
1760 self.reString = self.pattern
1760 except sre_constants.error:
1761 except sre_constants.error:
1761 warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
1762 warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
1762 SyntaxWarning, stacklevel=2)
1763 SyntaxWarning, stacklevel=2)
1763 raise
1764 raise
1764
1765
1765 self.name = _ustr(self)
1766 self.name = _ustr(self)
1766 self.errmsg = "Expected " + self.name
1767 self.errmsg = "Expected " + self.name
1767 #self.myException.msg = self.errmsg
1768 #self.myException.msg = self.errmsg
1768 self.mayIndexError = False
1769 self.mayIndexError = False
1769 self.mayReturnEmpty = True
1770 self.mayReturnEmpty = True
1770
1771
1771 def parseImpl( self, instring, loc, doActions=True ):
1772 def parseImpl( self, instring, loc, doActions=True ):
1772 result = self.re.match(instring,loc)
1773 result = self.re.match(instring,loc)
1773 if not result:
1774 if not result:
1774 exc = self.myException
1775 exc = self.myException
1775 exc.loc = loc
1776 exc.loc = loc
1776 exc.pstr = instring
1777 exc.pstr = instring
1777 raise exc
1778 raise exc
1778
1779
1779 loc = result.end()
1780 loc = result.end()
1780 d = result.groupdict()
1781 d = result.groupdict()
1781 ret = ParseResults(result.group())
1782 ret = ParseResults(result.group())
1782 if d:
1783 if d:
1783 for k in d:
1784 for k in d:
1784 ret[k] = d[k]
1785 ret[k] = d[k]
1785 return loc,ret
1786 return loc,ret
1786
1787
1787 def __str__( self ):
1788 def __str__( self ):
1788 try:
1789 try:
1789 return super(Regex,self).__str__()
1790 return super(Regex,self).__str__()
1790 except:
1791 except:
1791 pass
1792 pass
1792
1793
1793 if self.strRepr is None:
1794 if self.strRepr is None:
1794 self.strRepr = "Re:(%s)" % repr(self.pattern)
1795 self.strRepr = "Re:(%s)" % repr(self.pattern)
1795
1796
1796 return self.strRepr
1797 return self.strRepr
1797
1798
1798
1799
1799 class QuotedString(Token):
1800 class QuotedString(Token):
1800 """Token for matching strings that are delimited by quoting characters.
1801 """Token for matching strings that are delimited by quoting characters.
1801 """
1802 """
1802 def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None):
1803 def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None):
1803 """
1804 """
1804 Defined with the following parameters:
1805 Defined with the following parameters:
1805 - quoteChar - string of one or more characters defining the quote delimiting string
1806 - quoteChar - string of one or more characters defining the quote delimiting string
1806 - escChar - character to escape quotes, typically backslash (default=None)
1807 - escChar - character to escape quotes, typically backslash (default=None)
1807 - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
1808 - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
1808 - multiline - boolean indicating whether quotes can span multiple lines (default=False)
1809 - multiline - boolean indicating whether quotes can span multiple lines (default=False)
1809 - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)
1810 - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)
1810 - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar)
1811 - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar)
1811 """
1812 """
1812 super(QuotedString,self).__init__()
1813 super(QuotedString,self).__init__()
1813
1814
1814 # remove white space from quote chars - wont work anyway
1815 # remove white space from quote chars - wont work anyway
1815 quoteChar = quoteChar.strip()
1816 quoteChar = quoteChar.strip()
1816 if len(quoteChar) == 0:
1817 if len(quoteChar) == 0:
1817 warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
1818 warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
1818 raise SyntaxError()
1819 raise SyntaxError()
1819
1820
1820 if endQuoteChar is None:
1821 if endQuoteChar is None:
1821 endQuoteChar = quoteChar
1822 endQuoteChar = quoteChar
1822 else:
1823 else:
1823 endQuoteChar = endQuoteChar.strip()
1824 endQuoteChar = endQuoteChar.strip()
1824 if len(endQuoteChar) == 0:
1825 if len(endQuoteChar) == 0:
1825 warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
1826 warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
1826 raise SyntaxError()
1827 raise SyntaxError()
1827
1828
1828 self.quoteChar = quoteChar
1829 self.quoteChar = quoteChar
1829 self.quoteCharLen = len(quoteChar)
1830 self.quoteCharLen = len(quoteChar)
1830 self.firstQuoteChar = quoteChar[0]
1831 self.firstQuoteChar = quoteChar[0]
1831 self.endQuoteChar = endQuoteChar
1832 self.endQuoteChar = endQuoteChar
1832 self.endQuoteCharLen = len(endQuoteChar)
1833 self.endQuoteCharLen = len(endQuoteChar)
1833 self.escChar = escChar
1834 self.escChar = escChar
1834 self.escQuote = escQuote
1835 self.escQuote = escQuote
1835 self.unquoteResults = unquoteResults
1836 self.unquoteResults = unquoteResults
1836
1837
1837 if multiline:
1838 if multiline:
1838 self.flags = re.MULTILINE | re.DOTALL
1839 self.flags = re.MULTILINE | re.DOTALL
1839 self.pattern = r'%s(?:[^%s%s]' % \
1840 self.pattern = r'%s(?:[^%s%s]' % \
1840 ( re.escape(self.quoteChar),
1841 ( re.escape(self.quoteChar),
1841 _escapeRegexRangeChars(self.endQuoteChar[0]),
1842 _escapeRegexRangeChars(self.endQuoteChar[0]),
1842 (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
1843 (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
1843 else:
1844 else:
1844 self.flags = 0
1845 self.flags = 0
1845 self.pattern = r'%s(?:[^%s\n\r%s]' % \
1846 self.pattern = r'%s(?:[^%s\n\r%s]' % \
1846 ( re.escape(self.quoteChar),
1847 ( re.escape(self.quoteChar),
1847 _escapeRegexRangeChars(self.endQuoteChar[0]),
1848 _escapeRegexRangeChars(self.endQuoteChar[0]),
1848 (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
1849 (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
1849 if len(self.endQuoteChar) > 1:
1850 if len(self.endQuoteChar) > 1:
1850 self.pattern += (
1851 self.pattern += (
1851 '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
1852 '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
1852 _escapeRegexRangeChars(self.endQuoteChar[i]))
1853 _escapeRegexRangeChars(self.endQuoteChar[i]))
1853 for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')'
1854 for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')'
1854 )
1855 )
1855 if escQuote:
1856 if escQuote:
1856 self.pattern += (r'|(?:%s)' % re.escape(escQuote))
1857 self.pattern += (r'|(?:%s)' % re.escape(escQuote))
1857 if escChar:
1858 if escChar:
1858 self.pattern += (r'|(?:%s.)' % re.escape(escChar))
1859 self.pattern += (r'|(?:%s.)' % re.escape(escChar))
1859 self.escCharReplacePattern = re.escape(self.escChar)+"(.)"
1860 self.escCharReplacePattern = re.escape(self.escChar)+"(.)"
1860 self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
1861 self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
1861
1862
1862 try:
1863 try:
1863 self.re = re.compile(self.pattern, self.flags)
1864 self.re = re.compile(self.pattern, self.flags)
1864 self.reString = self.pattern
1865 self.reString = self.pattern
1865 except sre_constants.error:
1866 except sre_constants.error:
1866 warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
1867 warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
1867 SyntaxWarning, stacklevel=2)
1868 SyntaxWarning, stacklevel=2)
1868 raise
1869 raise
1869
1870
1870 self.name = _ustr(self)
1871 self.name = _ustr(self)
1871 self.errmsg = "Expected " + self.name
1872 self.errmsg = "Expected " + self.name
1872 #self.myException.msg = self.errmsg
1873 #self.myException.msg = self.errmsg
1873 self.mayIndexError = False
1874 self.mayIndexError = False
1874 self.mayReturnEmpty = True
1875 self.mayReturnEmpty = True
1875
1876
1876 def parseImpl( self, instring, loc, doActions=True ):
1877 def parseImpl( self, instring, loc, doActions=True ):
1877 result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
1878 result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
1878 if not result:
1879 if not result:
1879 exc = self.myException
1880 exc = self.myException
1880 exc.loc = loc
1881 exc.loc = loc
1881 exc.pstr = instring
1882 exc.pstr = instring
1882 raise exc
1883 raise exc
1883
1884
1884 loc = result.end()
1885 loc = result.end()
1885 ret = result.group()
1886 ret = result.group()
1886
1887
1887 if self.unquoteResults:
1888 if self.unquoteResults:
1888
1889
1889 # strip off quotes
1890 # strip off quotes
1890 ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
1891 ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
1891
1892
1892 if isinstance(ret,basestring):
1893 if isinstance(ret,basestring):
1893 # replace escaped characters
1894 # replace escaped characters
1894 if self.escChar:
1895 if self.escChar:
1895 ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
1896 ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
1896
1897
1897 # replace escaped quotes
1898 # replace escaped quotes
1898 if self.escQuote:
1899 if self.escQuote:
1899 ret = ret.replace(self.escQuote, self.endQuoteChar)
1900 ret = ret.replace(self.escQuote, self.endQuoteChar)
1900
1901
1901 return loc, ret
1902 return loc, ret
1902
1903
1903 def __str__( self ):
1904 def __str__( self ):
1904 try:
1905 try:
1905 return super(QuotedString,self).__str__()
1906 return super(QuotedString,self).__str__()
1906 except:
1907 except:
1907 pass
1908 pass
1908
1909
1909 if self.strRepr is None:
1910 if self.strRepr is None:
1910 self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
1911 self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
1911
1912
1912 return self.strRepr
1913 return self.strRepr
1913
1914
1914
1915
1915 class CharsNotIn(Token):
1916 class CharsNotIn(Token):
1916 """Token for matching words composed of characters *not* in a given set.
1917 """Token for matching words composed of characters *not* in a given set.
1917 Defined with string containing all disallowed characters, and an optional
1918 Defined with string containing all disallowed characters, and an optional
1918 minimum, maximum, and/or exact length. The default value for min is 1 (a
1919 minimum, maximum, and/or exact length. The default value for min is 1 (a
1919 minimum value < 1 is not valid); the default values for max and exact
1920 minimum value < 1 is not valid); the default values for max and exact
1920 are 0, meaning no maximum or exact length restriction.
1921 are 0, meaning no maximum or exact length restriction.
1921 """
1922 """
1922 def __init__( self, notChars, min=1, max=0, exact=0 ):
1923 def __init__( self, notChars, min=1, max=0, exact=0 ):
1923 super(CharsNotIn,self).__init__()
1924 super(CharsNotIn,self).__init__()
1924 self.skipWhitespace = False
1925 self.skipWhitespace = False
1925 self.notChars = notChars
1926 self.notChars = notChars
1926
1927
1927 if min < 1:
1928 if min < 1:
1928 raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
1929 raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
1929
1930
1930 self.minLen = min
1931 self.minLen = min
1931
1932
1932 if max > 0:
1933 if max > 0:
1933 self.maxLen = max
1934 self.maxLen = max
1934 else:
1935 else:
1935 self.maxLen = _MAX_INT
1936 self.maxLen = _MAX_INT
1936
1937
1937 if exact > 0:
1938 if exact > 0:
1938 self.maxLen = exact
1939 self.maxLen = exact
1939 self.minLen = exact
1940 self.minLen = exact
1940
1941
1941 self.name = _ustr(self)
1942 self.name = _ustr(self)
1942 self.errmsg = "Expected " + self.name
1943 self.errmsg = "Expected " + self.name
1943 self.mayReturnEmpty = ( self.minLen == 0 )
1944 self.mayReturnEmpty = ( self.minLen == 0 )
1944 #self.myException.msg = self.errmsg
1945 #self.myException.msg = self.errmsg
1945 self.mayIndexError = False
1946 self.mayIndexError = False
1946
1947
1947 def parseImpl( self, instring, loc, doActions=True ):
1948 def parseImpl( self, instring, loc, doActions=True ):
1948 if instring[loc] in self.notChars:
1949 if instring[loc] in self.notChars:
1949 #~ raise ParseException( instring, loc, self.errmsg )
1950 #~ raise ParseException( instring, loc, self.errmsg )
1950 exc = self.myException
1951 exc = self.myException
1951 exc.loc = loc
1952 exc.loc = loc
1952 exc.pstr = instring
1953 exc.pstr = instring
1953 raise exc
1954 raise exc
1954
1955
1955 start = loc
1956 start = loc
1956 loc += 1
1957 loc += 1
1957 notchars = self.notChars
1958 notchars = self.notChars
1958 maxlen = min( start+self.maxLen, len(instring) )
1959 maxlen = min( start+self.maxLen, len(instring) )
1959 while loc < maxlen and \
1960 while loc < maxlen and \
1960 (instring[loc] not in notchars):
1961 (instring[loc] not in notchars):
1961 loc += 1
1962 loc += 1
1962
1963
1963 if loc - start < self.minLen:
1964 if loc - start < self.minLen:
1964 #~ raise ParseException( instring, loc, self.errmsg )
1965 #~ raise ParseException( instring, loc, self.errmsg )
1965 exc = self.myException
1966 exc = self.myException
1966 exc.loc = loc
1967 exc.loc = loc
1967 exc.pstr = instring
1968 exc.pstr = instring
1968 raise exc
1969 raise exc
1969
1970
1970 return loc, instring[start:loc]
1971 return loc, instring[start:loc]
1971
1972
1972 def __str__( self ):
1973 def __str__( self ):
1973 try:
1974 try:
1974 return super(CharsNotIn, self).__str__()
1975 return super(CharsNotIn, self).__str__()
1975 except:
1976 except:
1976 pass
1977 pass
1977
1978
1978 if self.strRepr is None:
1979 if self.strRepr is None:
1979 if len(self.notChars) > 4:
1980 if len(self.notChars) > 4:
1980 self.strRepr = "!W:(%s...)" % self.notChars[:4]
1981 self.strRepr = "!W:(%s...)" % self.notChars[:4]
1981 else:
1982 else:
1982 self.strRepr = "!W:(%s)" % self.notChars
1983 self.strRepr = "!W:(%s)" % self.notChars
1983
1984
1984 return self.strRepr
1985 return self.strRepr
1985
1986
1986 class White(Token):
1987 class White(Token):
1987 """Special matching class for matching whitespace. Normally, whitespace is ignored
1988 """Special matching class for matching whitespace. Normally, whitespace is ignored
1988 by pyparsing grammars. This class is included when some whitespace structures
1989 by pyparsing grammars. This class is included when some whitespace structures
1989 are significant. Define with a string containing the whitespace characters to be
1990 are significant. Define with a string containing the whitespace characters to be
1990 matched; default is " \\t\\r\\n". Also takes optional min, max, and exact arguments,
1991 matched; default is " \\t\\r\\n". Also takes optional min, max, and exact arguments,
1991 as defined for the Word class."""
1992 as defined for the Word class."""
1992 whiteStrs = {
1993 whiteStrs = {
1993 " " : "<SPC>",
1994 " " : "<SPC>",
1994 "\t": "<TAB>",
1995 "\t": "<TAB>",
1995 "\n": "<LF>",
1996 "\n": "<LF>",
1996 "\r": "<CR>",
1997 "\r": "<CR>",
1997 "\f": "<FF>",
1998 "\f": "<FF>",
1998 }
1999 }
1999 def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
2000 def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
2000 super(White,self).__init__()
2001 super(White,self).__init__()
2001 self.matchWhite = ws
2002 self.matchWhite = ws
2002 self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) )
2003 self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) )
2003 #~ self.leaveWhitespace()
2004 #~ self.leaveWhitespace()
2004 self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite]))
2005 self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite]))
2005 self.mayReturnEmpty = True
2006 self.mayReturnEmpty = True
2006 self.errmsg = "Expected " + self.name
2007 self.errmsg = "Expected " + self.name
2007 #self.myException.msg = self.errmsg
2008 #self.myException.msg = self.errmsg
2008
2009
2009 self.minLen = min
2010 self.minLen = min
2010
2011
2011 if max > 0:
2012 if max > 0:
2012 self.maxLen = max
2013 self.maxLen = max
2013 else:
2014 else:
2014 self.maxLen = _MAX_INT
2015 self.maxLen = _MAX_INT
2015
2016
2016 if exact > 0:
2017 if exact > 0:
2017 self.maxLen = exact
2018 self.maxLen = exact
2018 self.minLen = exact
2019 self.minLen = exact
2019
2020
2020 def parseImpl( self, instring, loc, doActions=True ):
2021 def parseImpl( self, instring, loc, doActions=True ):
2021 if not(instring[ loc ] in self.matchWhite):
2022 if not(instring[ loc ] in self.matchWhite):
2022 #~ raise ParseException( instring, loc, self.errmsg )
2023 #~ raise ParseException( instring, loc, self.errmsg )
2023 exc = self.myException
2024 exc = self.myException
2024 exc.loc = loc
2025 exc.loc = loc
2025 exc.pstr = instring
2026 exc.pstr = instring
2026 raise exc
2027 raise exc
2027 start = loc
2028 start = loc
2028 loc += 1
2029 loc += 1
2029 maxloc = start + self.maxLen
2030 maxloc = start + self.maxLen
2030 maxloc = min( maxloc, len(instring) )
2031 maxloc = min( maxloc, len(instring) )
2031 while loc < maxloc and instring[loc] in self.matchWhite:
2032 while loc < maxloc and instring[loc] in self.matchWhite:
2032 loc += 1
2033 loc += 1
2033
2034
2034 if loc - start < self.minLen:
2035 if loc - start < self.minLen:
2035 #~ raise ParseException( instring, loc, self.errmsg )
2036 #~ raise ParseException( instring, loc, self.errmsg )
2036 exc = self.myException
2037 exc = self.myException
2037 exc.loc = loc
2038 exc.loc = loc
2038 exc.pstr = instring
2039 exc.pstr = instring
2039 raise exc
2040 raise exc
2040
2041
2041 return loc, instring[start:loc]
2042 return loc, instring[start:loc]
2042
2043
2043
2044
2044 class _PositionToken(Token):
2045 class _PositionToken(Token):
2045 def __init__( self ):
2046 def __init__( self ):
2046 super(_PositionToken,self).__init__()
2047 super(_PositionToken,self).__init__()
2047 self.name=self.__class__.__name__
2048 self.name=self.__class__.__name__
2048 self.mayReturnEmpty = True
2049 self.mayReturnEmpty = True
2049 self.mayIndexError = False
2050 self.mayIndexError = False
2050
2051
2051 class GoToColumn(_PositionToken):
2052 class GoToColumn(_PositionToken):
2052 """Token to advance to a specific column of input text; useful for tabular report scraping."""
2053 """Token to advance to a specific column of input text; useful for tabular report scraping."""
2053 def __init__( self, colno ):
2054 def __init__( self, colno ):
2054 super(GoToColumn,self).__init__()
2055 super(GoToColumn,self).__init__()
2055 self.col = colno
2056 self.col = colno
2056
2057
2057 def preParse( self, instring, loc ):
2058 def preParse( self, instring, loc ):
2058 if col(loc,instring) != self.col:
2059 if col(loc,instring) != self.col:
2059 instrlen = len(instring)
2060 instrlen = len(instring)
2060 if self.ignoreExprs:
2061 if self.ignoreExprs:
2061 loc = self._skipIgnorables( instring, loc )
2062 loc = self._skipIgnorables( instring, loc )
2062 while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
2063 while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
2063 loc += 1
2064 loc += 1
2064 return loc
2065 return loc
2065
2066
2066 def parseImpl( self, instring, loc, doActions=True ):
2067 def parseImpl( self, instring, loc, doActions=True ):
2067 thiscol = col( loc, instring )
2068 thiscol = col( loc, instring )
2068 if thiscol > self.col:
2069 if thiscol > self.col:
2069 raise ParseException( instring, loc, "Text not in expected column", self )
2070 raise ParseException( instring, loc, "Text not in expected column", self )
2070 newloc = loc + self.col - thiscol
2071 newloc = loc + self.col - thiscol
2071 ret = instring[ loc: newloc ]
2072 ret = instring[ loc: newloc ]
2072 return newloc, ret
2073 return newloc, ret
2073
2074
2074 class LineStart(_PositionToken):
2075 class LineStart(_PositionToken):
2075 """Matches if current position is at the beginning of a line within the parse string"""
2076 """Matches if current position is at the beginning of a line within the parse string"""
2076 def __init__( self ):
2077 def __init__( self ):
2077 super(LineStart,self).__init__()
2078 super(LineStart,self).__init__()
2078 self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
2079 self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
2079 self.errmsg = "Expected start of line"
2080 self.errmsg = "Expected start of line"
2080 #self.myException.msg = self.errmsg
2081 #self.myException.msg = self.errmsg
2081
2082
2082 def preParse( self, instring, loc ):
2083 def preParse( self, instring, loc ):
2083 preloc = super(LineStart,self).preParse(instring,loc)
2084 preloc = super(LineStart,self).preParse(instring,loc)
2084 if instring[preloc] == "\n":
2085 if instring[preloc] == "\n":
2085 loc += 1
2086 loc += 1
2086 return loc
2087 return loc
2087
2088
2088 def parseImpl( self, instring, loc, doActions=True ):
2089 def parseImpl( self, instring, loc, doActions=True ):
2089 if not( loc==0 or
2090 if not( loc==0 or
2090 (loc == self.preParse( instring, 0 )) or
2091 (loc == self.preParse( instring, 0 )) or
2091 (instring[loc-1] == "\n") ): #col(loc, instring) != 1:
2092 (instring[loc-1] == "\n") ): #col(loc, instring) != 1:
2092 #~ raise ParseException( instring, loc, "Expected start of line" )
2093 #~ raise ParseException( instring, loc, "Expected start of line" )
2093 exc = self.myException
2094 exc = self.myException
2094 exc.loc = loc
2095 exc.loc = loc
2095 exc.pstr = instring
2096 exc.pstr = instring
2096 raise exc
2097 raise exc
2097 return loc, []
2098 return loc, []
2098
2099
2099 class LineEnd(_PositionToken):
2100 class LineEnd(_PositionToken):
2100 """Matches if current position is at the end of a line within the parse string"""
2101 """Matches if current position is at the end of a line within the parse string"""
2101 def __init__( self ):
2102 def __init__( self ):
2102 super(LineEnd,self).__init__()
2103 super(LineEnd,self).__init__()
2103 self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
2104 self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
2104 self.errmsg = "Expected end of line"
2105 self.errmsg = "Expected end of line"
2105 #self.myException.msg = self.errmsg
2106 #self.myException.msg = self.errmsg
2106
2107
2107 def parseImpl( self, instring, loc, doActions=True ):
2108 def parseImpl( self, instring, loc, doActions=True ):
2108 if loc<len(instring):
2109 if loc<len(instring):
2109 if instring[loc] == "\n":
2110 if instring[loc] == "\n":
2110 return loc+1, "\n"
2111 return loc+1, "\n"
2111 else:
2112 else:
2112 #~ raise ParseException( instring, loc, "Expected end of line" )
2113 #~ raise ParseException( instring, loc, "Expected end of line" )
2113 exc = self.myException
2114 exc = self.myException
2114 exc.loc = loc
2115 exc.loc = loc
2115 exc.pstr = instring
2116 exc.pstr = instring
2116 raise exc
2117 raise exc
2117 elif loc == len(instring):
2118 elif loc == len(instring):
2118 return loc+1, []
2119 return loc+1, []
2119 else:
2120 else:
2120 exc = self.myException
2121 exc = self.myException
2121 exc.loc = loc
2122 exc.loc = loc
2122 exc.pstr = instring
2123 exc.pstr = instring
2123 raise exc
2124 raise exc
2124
2125
2125 class StringStart(_PositionToken):
2126 class StringStart(_PositionToken):
2126 """Matches if current position is at the beginning of the parse string"""
2127 """Matches if current position is at the beginning of the parse string"""
2127 def __init__( self ):
2128 def __init__( self ):
2128 super(StringStart,self).__init__()
2129 super(StringStart,self).__init__()
2129 self.errmsg = "Expected start of text"
2130 self.errmsg = "Expected start of text"
2130 #self.myException.msg = self.errmsg
2131 #self.myException.msg = self.errmsg
2131
2132
2132 def parseImpl( self, instring, loc, doActions=True ):
2133 def parseImpl( self, instring, loc, doActions=True ):
2133 if loc != 0:
2134 if loc != 0:
2134 # see if entire string up to here is just whitespace and ignoreables
2135 # see if entire string up to here is just whitespace and ignoreables
2135 if loc != self.preParse( instring, 0 ):
2136 if loc != self.preParse( instring, 0 ):
2136 #~ raise ParseException( instring, loc, "Expected start of text" )
2137 #~ raise ParseException( instring, loc, "Expected start of text" )
2137 exc = self.myException
2138 exc = self.myException
2138 exc.loc = loc
2139 exc.loc = loc
2139 exc.pstr = instring
2140 exc.pstr = instring
2140 raise exc
2141 raise exc
2141 return loc, []
2142 return loc, []
2142
2143
2143 class StringEnd(_PositionToken):
2144 class StringEnd(_PositionToken):
2144 """Matches if current position is at the end of the parse string"""
2145 """Matches if current position is at the end of the parse string"""
2145 def __init__( self ):
2146 def __init__( self ):
2146 super(StringEnd,self).__init__()
2147 super(StringEnd,self).__init__()
2147 self.errmsg = "Expected end of text"
2148 self.errmsg = "Expected end of text"
2148 #self.myException.msg = self.errmsg
2149 #self.myException.msg = self.errmsg
2149
2150
2150 def parseImpl( self, instring, loc, doActions=True ):
2151 def parseImpl( self, instring, loc, doActions=True ):
2151 if loc < len(instring):
2152 if loc < len(instring):
2152 #~ raise ParseException( instring, loc, "Expected end of text" )
2153 #~ raise ParseException( instring, loc, "Expected end of text" )
2153 exc = self.myException
2154 exc = self.myException
2154 exc.loc = loc
2155 exc.loc = loc
2155 exc.pstr = instring
2156 exc.pstr = instring
2156 raise exc
2157 raise exc
2157 elif loc == len(instring):
2158 elif loc == len(instring):
2158 return loc+1, []
2159 return loc+1, []
2159 elif loc > len(instring):
2160 elif loc > len(instring):
2160 return loc, []
2161 return loc, []
2161 else:
2162 else:
2162 exc = self.myException
2163 exc = self.myException
2163 exc.loc = loc
2164 exc.loc = loc
2164 exc.pstr = instring
2165 exc.pstr = instring
2165 raise exc
2166 raise exc
2166
2167
2167 class WordStart(_PositionToken):
2168 class WordStart(_PositionToken):
2168 """Matches if the current position is at the beginning of a Word, and
2169 """Matches if the current position is at the beginning of a Word, and
2169 is not preceded by any character in a given set of wordChars
2170 is not preceded by any character in a given set of wordChars
2170 (default=printables). To emulate the \b behavior of regular expressions,
2171 (default=printables). To emulate the \b behavior of regular expressions,
2171 use WordStart(alphanums). WordStart will also match at the beginning of
2172 use WordStart(alphanums). WordStart will also match at the beginning of
2172 the string being parsed, or at the beginning of a line.
2173 the string being parsed, or at the beginning of a line.
2173 """
2174 """
2174 def __init__(self, wordChars = printables):
2175 def __init__(self, wordChars = printables):
2175 super(WordStart,self).__init__()
2176 super(WordStart,self).__init__()
2176 self.wordChars = _str2dict(wordChars)
2177 self.wordChars = _str2dict(wordChars)
2177 self.errmsg = "Not at the start of a word"
2178 self.errmsg = "Not at the start of a word"
2178
2179
2179 def parseImpl(self, instring, loc, doActions=True ):
2180 def parseImpl(self, instring, loc, doActions=True ):
2180 if loc != 0:
2181 if loc != 0:
2181 if (instring[loc-1] in self.wordChars or
2182 if (instring[loc-1] in self.wordChars or
2182 instring[loc] not in self.wordChars):
2183 instring[loc] not in self.wordChars):
2183 exc = self.myException
2184 exc = self.myException
2184 exc.loc = loc
2185 exc.loc = loc
2185 exc.pstr = instring
2186 exc.pstr = instring
2186 raise exc
2187 raise exc
2187 return loc, []
2188 return loc, []
2188
2189
2189 class WordEnd(_PositionToken):
2190 class WordEnd(_PositionToken):
2190 """Matches if the current position is at the end of a Word, and
2191 """Matches if the current position is at the end of a Word, and
2191 is not followed by any character in a given set of wordChars
2192 is not followed by any character in a given set of wordChars
2192 (default=printables). To emulate the \b behavior of regular expressions,
2193 (default=printables). To emulate the \b behavior of regular expressions,
2193 use WordEnd(alphanums). WordEnd will also match at the end of
2194 use WordEnd(alphanums). WordEnd will also match at the end of
2194 the string being parsed, or at the end of a line.
2195 the string being parsed, or at the end of a line.
2195 """
2196 """
2196 def __init__(self, wordChars = printables):
2197 def __init__(self, wordChars = printables):
2197 super(WordEnd,self).__init__()
2198 super(WordEnd,self).__init__()
2198 self.wordChars = _str2dict(wordChars)
2199 self.wordChars = _str2dict(wordChars)
2199 self.skipWhitespace = False
2200 self.skipWhitespace = False
2200 self.errmsg = "Not at the end of a word"
2201 self.errmsg = "Not at the end of a word"
2201
2202
2202 def parseImpl(self, instring, loc, doActions=True ):
2203 def parseImpl(self, instring, loc, doActions=True ):
2203 instrlen = len(instring)
2204 instrlen = len(instring)
2204 if instrlen>0 and loc<instrlen:
2205 if instrlen>0 and loc<instrlen:
2205 if (instring[loc] in self.wordChars or
2206 if (instring[loc] in self.wordChars or
2206 instring[loc-1] not in self.wordChars):
2207 instring[loc-1] not in self.wordChars):
2207 #~ raise ParseException( instring, loc, "Expected end of word" )
2208 #~ raise ParseException( instring, loc, "Expected end of word" )
2208 exc = self.myException
2209 exc = self.myException
2209 exc.loc = loc
2210 exc.loc = loc
2210 exc.pstr = instring
2211 exc.pstr = instring
2211 raise exc
2212 raise exc
2212 return loc, []
2213 return loc, []
2213
2214
2214
2215
2215 class ParseExpression(ParserElement):
2216 class ParseExpression(ParserElement):
2216 """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
2217 """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
2217 def __init__( self, exprs, savelist = False ):
2218 def __init__( self, exprs, savelist = False ):
2218 super(ParseExpression,self).__init__(savelist)
2219 super(ParseExpression,self).__init__(savelist)
2219 if isinstance( exprs, list ):
2220 if isinstance( exprs, list ):
2220 self.exprs = exprs
2221 self.exprs = exprs
2221 elif isinstance( exprs, basestring ):
2222 elif isinstance( exprs, basestring ):
2222 self.exprs = [ Literal( exprs ) ]
2223 self.exprs = [ Literal( exprs ) ]
2223 else:
2224 else:
2224 try:
2225 try:
2225 self.exprs = list( exprs )
2226 self.exprs = list( exprs )
2226 except TypeError:
2227 except TypeError:
2227 self.exprs = [ exprs ]
2228 self.exprs = [ exprs ]
2228 self.callPreparse = False
2229 self.callPreparse = False
2229
2230
2230 def __getitem__( self, i ):
2231 def __getitem__( self, i ):
2231 return self.exprs[i]
2232 return self.exprs[i]
2232
2233
2233 def append( self, other ):
2234 def append( self, other ):
2234 self.exprs.append( other )
2235 self.exprs.append( other )
2235 self.strRepr = None
2236 self.strRepr = None
2236 return self
2237 return self
2237
2238
2238 def leaveWhitespace( self ):
2239 def leaveWhitespace( self ):
2239 """Extends leaveWhitespace defined in base class, and also invokes leaveWhitespace on
2240 """Extends leaveWhitespace defined in base class, and also invokes leaveWhitespace on
2240 all contained expressions."""
2241 all contained expressions."""
2241 self.skipWhitespace = False
2242 self.skipWhitespace = False
2242 self.exprs = [ e.copy() for e in self.exprs ]
2243 self.exprs = [ e.copy() for e in self.exprs ]
2243 for e in self.exprs:
2244 for e in self.exprs:
2244 e.leaveWhitespace()
2245 e.leaveWhitespace()
2245 return self
2246 return self
2246
2247
2247 def ignore( self, other ):
2248 def ignore( self, other ):
2248 if isinstance( other, Suppress ):
2249 if isinstance( other, Suppress ):
2249 if other not in self.ignoreExprs:
2250 if other not in self.ignoreExprs:
2250 super( ParseExpression, self).ignore( other )
2251 super( ParseExpression, self).ignore( other )
2251 for e in self.exprs:
2252 for e in self.exprs:
2252 e.ignore( self.ignoreExprs[-1] )
2253 e.ignore( self.ignoreExprs[-1] )
2253 else:
2254 else:
2254 super( ParseExpression, self).ignore( other )
2255 super( ParseExpression, self).ignore( other )
2255 for e in self.exprs:
2256 for e in self.exprs:
2256 e.ignore( self.ignoreExprs[-1] )
2257 e.ignore( self.ignoreExprs[-1] )
2257 return self
2258 return self
2258
2259
2259 def __str__( self ):
2260 def __str__( self ):
2260 try:
2261 try:
2261 return super(ParseExpression,self).__str__()
2262 return super(ParseExpression,self).__str__()
2262 except:
2263 except:
2263 pass
2264 pass
2264
2265
2265 if self.strRepr is None:
2266 if self.strRepr is None:
2266 self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
2267 self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
2267 return self.strRepr
2268 return self.strRepr
2268
2269
2269 def streamline( self ):
2270 def streamline( self ):
2270 super(ParseExpression,self).streamline()
2271 super(ParseExpression,self).streamline()
2271
2272
2272 for e in self.exprs:
2273 for e in self.exprs:
2273 e.streamline()
2274 e.streamline()
2274
2275
2275 # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
2276 # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
2276 # but only if there are no parse actions or resultsNames on the nested And's
2277 # but only if there are no parse actions or resultsNames on the nested And's
2277 # (likewise for Or's and MatchFirst's)
2278 # (likewise for Or's and MatchFirst's)
2278 if ( len(self.exprs) == 2 ):
2279 if ( len(self.exprs) == 2 ):
2279 other = self.exprs[0]
2280 other = self.exprs[0]
2280 if ( isinstance( other, self.__class__ ) and
2281 if ( isinstance( other, self.__class__ ) and
2281 not(other.parseAction) and
2282 not(other.parseAction) and
2282 other.resultsName is None and
2283 other.resultsName is None and
2283 not other.debug ):
2284 not other.debug ):
2284 self.exprs = other.exprs[:] + [ self.exprs[1] ]
2285 self.exprs = other.exprs[:] + [ self.exprs[1] ]
2285 self.strRepr = None
2286 self.strRepr = None
2286 self.mayReturnEmpty |= other.mayReturnEmpty
2287 self.mayReturnEmpty |= other.mayReturnEmpty
2287 self.mayIndexError |= other.mayIndexError
2288 self.mayIndexError |= other.mayIndexError
2288
2289
2289 other = self.exprs[-1]
2290 other = self.exprs[-1]
2290 if ( isinstance( other, self.__class__ ) and
2291 if ( isinstance( other, self.__class__ ) and
2291 not(other.parseAction) and
2292 not(other.parseAction) and
2292 other.resultsName is None and
2293 other.resultsName is None and
2293 not other.debug ):
2294 not other.debug ):
2294 self.exprs = self.exprs[:-1] + other.exprs[:]
2295 self.exprs = self.exprs[:-1] + other.exprs[:]
2295 self.strRepr = None
2296 self.strRepr = None
2296 self.mayReturnEmpty |= other.mayReturnEmpty
2297 self.mayReturnEmpty |= other.mayReturnEmpty
2297 self.mayIndexError |= other.mayIndexError
2298 self.mayIndexError |= other.mayIndexError
2298
2299
2299 return self
2300 return self
2300
2301
2301 def setResultsName( self, name, listAllMatches=False ):
2302 def setResultsName( self, name, listAllMatches=False ):
2302 ret = super(ParseExpression,self).setResultsName(name,listAllMatches)
2303 ret = super(ParseExpression,self).setResultsName(name,listAllMatches)
2303 return ret
2304 return ret
2304
2305
2305 def validate( self, validateTrace=[] ):
2306 def validate( self, validateTrace=[] ):
2306 tmp = validateTrace[:]+[self]
2307 tmp = validateTrace[:]+[self]
2307 for e in self.exprs:
2308 for e in self.exprs:
2308 e.validate(tmp)
2309 e.validate(tmp)
2309 self.checkRecursion( [] )
2310 self.checkRecursion( [] )
2310
2311
2311 class And(ParseExpression):
2312 class And(ParseExpression):
2312 """Requires all given ParseExpressions to be found in the given order.
2313 """Requires all given ParseExpressions to be found in the given order.
2313 Expressions may be separated by whitespace.
2314 Expressions may be separated by whitespace.
2314 May be constructed using the '+' operator.
2315 May be constructed using the '+' operator.
2315 """
2316 """
2316
2317
2317 class _ErrorStop(Empty):
2318 class _ErrorStop(Empty):
2318 def __init__(self, *args, **kwargs):
2319 def __init__(self, *args, **kwargs):
2319 super(Empty,self).__init__(*args, **kwargs)
2320 super(Empty,self).__init__(*args, **kwargs)
2320 self.leaveWhitespace()
2321 self.leaveWhitespace()
2321
2322
2322 def __init__( self, exprs, savelist = True ):
2323 def __init__( self, exprs, savelist = True ):
2323 super(And,self).__init__(exprs, savelist)
2324 super(And,self).__init__(exprs, savelist)
2324 self.mayReturnEmpty = True
2325 self.mayReturnEmpty = True
2325 for e in self.exprs:
2326 for e in self.exprs:
2326 if not e.mayReturnEmpty:
2327 if not e.mayReturnEmpty:
2327 self.mayReturnEmpty = False
2328 self.mayReturnEmpty = False
2328 break
2329 break
2329 self.setWhitespaceChars( exprs[0].whiteChars )
2330 self.setWhitespaceChars( exprs[0].whiteChars )
2330 self.skipWhitespace = exprs[0].skipWhitespace
2331 self.skipWhitespace = exprs[0].skipWhitespace
2331 self.callPreparse = True
2332 self.callPreparse = True
2332
2333
2333 def parseImpl( self, instring, loc, doActions=True ):
2334 def parseImpl( self, instring, loc, doActions=True ):
2334 # pass False as last arg to _parse for first element, since we already
2335 # pass False as last arg to _parse for first element, since we already
2335 # pre-parsed the string as part of our And pre-parsing
2336 # pre-parsed the string as part of our And pre-parsing
2336 loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
2337 loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
2337 errorStop = False
2338 errorStop = False
2338 for e in self.exprs[1:]:
2339 for e in self.exprs[1:]:
2339 if isinstance(e, And._ErrorStop):
2340 if isinstance(e, And._ErrorStop):
2340 errorStop = True
2341 errorStop = True
2341 continue
2342 continue
2342 if errorStop:
2343 if errorStop:
2343 try:
2344 try:
2344 loc, exprtokens = e._parse( instring, loc, doActions )
2345 loc, exprtokens = e._parse( instring, loc, doActions )
2345 except ParseSyntaxException:
2346 except ParseSyntaxException:
2346 raise
2347 raise
2347 except ParseBaseException, pe:
2348 except ParseBaseException, pe:
2348 raise ParseSyntaxException(pe)
2349 raise ParseSyntaxException(pe)
2349 except IndexError, ie:
2350 except IndexError, ie:
2350 raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
2351 raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
2351 else:
2352 else:
2352 loc, exprtokens = e._parse( instring, loc, doActions )
2353 loc, exprtokens = e._parse( instring, loc, doActions )
2353 if exprtokens or exprtokens.keys():
2354 if exprtokens or exprtokens.keys():
2354 resultlist += exprtokens
2355 resultlist += exprtokens
2355 return loc, resultlist
2356 return loc, resultlist
2356
2357
2357 def __iadd__(self, other ):
2358 def __iadd__(self, other ):
2358 if isinstance( other, basestring ):
2359 if isinstance( other, basestring ):
2359 other = Literal( other )
2360 other = Literal( other )
2360 return self.append( other ) #And( [ self, other ] )
2361 return self.append( other ) #And( [ self, other ] )
2361
2362
2362 def checkRecursion( self, parseElementList ):
2363 def checkRecursion( self, parseElementList ):
2363 subRecCheckList = parseElementList[:] + [ self ]
2364 subRecCheckList = parseElementList[:] + [ self ]
2364 for e in self.exprs:
2365 for e in self.exprs:
2365 e.checkRecursion( subRecCheckList )
2366 e.checkRecursion( subRecCheckList )
2366 if not e.mayReturnEmpty:
2367 if not e.mayReturnEmpty:
2367 break
2368 break
2368
2369
2369 def __str__( self ):
2370 def __str__( self ):
2370 if hasattr(self,"name"):
2371 if hasattr(self,"name"):
2371 return self.name
2372 return self.name
2372
2373
2373 if self.strRepr is None:
2374 if self.strRepr is None:
2374 self.strRepr = "{" + " ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
2375 self.strRepr = "{" + " ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
2375
2376
2376 return self.strRepr
2377 return self.strRepr
2377
2378
2378
2379
2379 class Or(ParseExpression):
2380 class Or(ParseExpression):
2380 """Requires that at least one ParseExpression is found.
2381 """Requires that at least one ParseExpression is found.
2381 If two expressions match, the expression that matches the longest string will be used.
2382 If two expressions match, the expression that matches the longest string will be used.
2382 May be constructed using the '^' operator.
2383 May be constructed using the '^' operator.
2383 """
2384 """
2384 def __init__( self, exprs, savelist = False ):
2385 def __init__( self, exprs, savelist = False ):
2385 super(Or,self).__init__(exprs, savelist)
2386 super(Or,self).__init__(exprs, savelist)
2386 self.mayReturnEmpty = False
2387 self.mayReturnEmpty = False
2387 for e in self.exprs:
2388 for e in self.exprs:
2388 if e.mayReturnEmpty:
2389 if e.mayReturnEmpty:
2389 self.mayReturnEmpty = True
2390 self.mayReturnEmpty = True
2390 break
2391 break
2391
2392
2392 def parseImpl( self, instring, loc, doActions=True ):
2393 def parseImpl( self, instring, loc, doActions=True ):
2393 maxExcLoc = -1
2394 maxExcLoc = -1
2394 maxMatchLoc = -1
2395 maxMatchLoc = -1
2395 maxException = None
2396 maxException = None
2396 for e in self.exprs:
2397 for e in self.exprs:
2397 try:
2398 try:
2398 loc2 = e.tryParse( instring, loc )
2399 loc2 = e.tryParse( instring, loc )
2399 except ParseException, err:
2400 except ParseException, err:
2400 if err.loc > maxExcLoc:
2401 if err.loc > maxExcLoc:
2401 maxException = err
2402 maxException = err
2402 maxExcLoc = err.loc
2403 maxExcLoc = err.loc
2403 except IndexError:
2404 except IndexError:
2404 if len(instring) > maxExcLoc:
2405 if len(instring) > maxExcLoc:
2405 maxException = ParseException(instring,len(instring),e.errmsg,self)
2406 maxException = ParseException(instring,len(instring),e.errmsg,self)
2406 maxExcLoc = len(instring)
2407 maxExcLoc = len(instring)
2407 else:
2408 else:
2408 if loc2 > maxMatchLoc:
2409 if loc2 > maxMatchLoc:
2409 maxMatchLoc = loc2
2410 maxMatchLoc = loc2
2410 maxMatchExp = e
2411 maxMatchExp = e
2411
2412
2412 if maxMatchLoc < 0:
2413 if maxMatchLoc < 0:
2413 if maxException is not None:
2414 if maxException is not None:
2414 raise maxException
2415 raise maxException
2415 else:
2416 else:
2416 raise ParseException(instring, loc, "no defined alternatives to match", self)
2417 raise ParseException(instring, loc, "no defined alternatives to match", self)
2417
2418
2418 return maxMatchExp._parse( instring, loc, doActions )
2419 return maxMatchExp._parse( instring, loc, doActions )
2419
2420
2420 def __ixor__(self, other ):
2421 def __ixor__(self, other ):
2421 if isinstance( other, basestring ):
2422 if isinstance( other, basestring ):
2422 other = Literal( other )
2423 other = Literal( other )
2423 return self.append( other ) #Or( [ self, other ] )
2424 return self.append( other ) #Or( [ self, other ] )
2424
2425
2425 def __str__( self ):
2426 def __str__( self ):
2426 if hasattr(self,"name"):
2427 if hasattr(self,"name"):
2427 return self.name
2428 return self.name
2428
2429
2429 if self.strRepr is None:
2430 if self.strRepr is None:
2430 self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
2431 self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
2431
2432
2432 return self.strRepr
2433 return self.strRepr
2433
2434
2434 def checkRecursion( self, parseElementList ):
2435 def checkRecursion( self, parseElementList ):
2435 subRecCheckList = parseElementList[:] + [ self ]
2436 subRecCheckList = parseElementList[:] + [ self ]
2436 for e in self.exprs:
2437 for e in self.exprs:
2437 e.checkRecursion( subRecCheckList )
2438 e.checkRecursion( subRecCheckList )
2438
2439
2439
2440
2440 class MatchFirst(ParseExpression):
2441 class MatchFirst(ParseExpression):
2441 """Requires that at least one ParseExpression is found.
2442 """Requires that at least one ParseExpression is found.
2442 If two expressions match, the first one listed is the one that will match.
2443 If two expressions match, the first one listed is the one that will match.
2443 May be constructed using the '|' operator.
2444 May be constructed using the '|' operator.
2444 """
2445 """
2445 def __init__( self, exprs, savelist = False ):
2446 def __init__( self, exprs, savelist = False ):
2446 super(MatchFirst,self).__init__(exprs, savelist)
2447 super(MatchFirst,self).__init__(exprs, savelist)
2447 if exprs:
2448 if exprs:
2448 self.mayReturnEmpty = False
2449 self.mayReturnEmpty = False
2449 for e in self.exprs:
2450 for e in self.exprs:
2450 if e.mayReturnEmpty:
2451 if e.mayReturnEmpty:
2451 self.mayReturnEmpty = True
2452 self.mayReturnEmpty = True
2452 break
2453 break
2453 else:
2454 else:
2454 self.mayReturnEmpty = True
2455 self.mayReturnEmpty = True
2455
2456
2456 def parseImpl( self, instring, loc, doActions=True ):
2457 def parseImpl( self, instring, loc, doActions=True ):
2457 maxExcLoc = -1
2458 maxExcLoc = -1
2458 maxException = None
2459 maxException = None
2459 for e in self.exprs:
2460 for e in self.exprs:
2460 try:
2461 try:
2461 ret = e._parse( instring, loc, doActions )
2462 ret = e._parse( instring, loc, doActions )
2462 return ret
2463 return ret
2463 except ParseException, err:
2464 except ParseException, err:
2464 if err.loc > maxExcLoc:
2465 if err.loc > maxExcLoc:
2465 maxException = err
2466 maxException = err
2466 maxExcLoc = err.loc
2467 maxExcLoc = err.loc
2467 except IndexError:
2468 except IndexError:
2468 if len(instring) > maxExcLoc:
2469 if len(instring) > maxExcLoc:
2469 maxException = ParseException(instring,len(instring),e.errmsg,self)
2470 maxException = ParseException(instring,len(instring),e.errmsg,self)
2470 maxExcLoc = len(instring)
2471 maxExcLoc = len(instring)
2471
2472
2472 # only got here if no expression matched, raise exception for match that made it the furthest
2473 # only got here if no expression matched, raise exception for match that made it the furthest
2473 else:
2474 else:
2474 if maxException is not None:
2475 if maxException is not None:
2475 raise maxException
2476 raise maxException
2476 else:
2477 else:
2477 raise ParseException(instring, loc, "no defined alternatives to match", self)
2478 raise ParseException(instring, loc, "no defined alternatives to match", self)
2478
2479
2479 def __ior__(self, other ):
2480 def __ior__(self, other ):
2480 if isinstance( other, basestring ):
2481 if isinstance( other, basestring ):
2481 other = Literal( other )
2482 other = Literal( other )
2482 return self.append( other ) #MatchFirst( [ self, other ] )
2483 return self.append( other ) #MatchFirst( [ self, other ] )
2483
2484
2484 def __str__( self ):
2485 def __str__( self ):
2485 if hasattr(self,"name"):
2486 if hasattr(self,"name"):
2486 return self.name
2487 return self.name
2487
2488
2488 if self.strRepr is None:
2489 if self.strRepr is None:
2489 self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
2490 self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
2490
2491
2491 return self.strRepr
2492 return self.strRepr
2492
2493
2493 def checkRecursion( self, parseElementList ):
2494 def checkRecursion( self, parseElementList ):
2494 subRecCheckList = parseElementList[:] + [ self ]
2495 subRecCheckList = parseElementList[:] + [ self ]
2495 for e in self.exprs:
2496 for e in self.exprs:
2496 e.checkRecursion( subRecCheckList )
2497 e.checkRecursion( subRecCheckList )
2497
2498
2498
2499
2499 class Each(ParseExpression):
2500 class Each(ParseExpression):
2500 """Requires all given ParseExpressions to be found, but in any order.
2501 """Requires all given ParseExpressions to be found, but in any order.
2501 Expressions may be separated by whitespace.
2502 Expressions may be separated by whitespace.
2502 May be constructed using the '&' operator.
2503 May be constructed using the '&' operator.
2503 """
2504 """
2504 def __init__( self, exprs, savelist = True ):
2505 def __init__( self, exprs, savelist = True ):
2505 super(Each,self).__init__(exprs, savelist)
2506 super(Each,self).__init__(exprs, savelist)
2506 self.mayReturnEmpty = True
2507 self.mayReturnEmpty = True
2507 for e in self.exprs:
2508 for e in self.exprs:
2508 if not e.mayReturnEmpty:
2509 if not e.mayReturnEmpty:
2509 self.mayReturnEmpty = False
2510 self.mayReturnEmpty = False
2510 break
2511 break
2511 self.skipWhitespace = True
2512 self.skipWhitespace = True
2512 self.initExprGroups = True
2513 self.initExprGroups = True
2513
2514
2514 def parseImpl( self, instring, loc, doActions=True ):
2515 def parseImpl( self, instring, loc, doActions=True ):
2515 if self.initExprGroups:
2516 if self.initExprGroups:
2516 self.optionals = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
2517 self.optionals = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
2517 self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
2518 self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
2518 self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
2519 self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
2519 self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
2520 self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
2520 self.required += self.multirequired
2521 self.required += self.multirequired
2521 self.initExprGroups = False
2522 self.initExprGroups = False
2522 tmpLoc = loc
2523 tmpLoc = loc
2523 tmpReqd = self.required[:]
2524 tmpReqd = self.required[:]
2524 tmpOpt = self.optionals[:]
2525 tmpOpt = self.optionals[:]
2525 matchOrder = []
2526 matchOrder = []
2526
2527
2527 keepMatching = True
2528 keepMatching = True
2528 while keepMatching:
2529 while keepMatching:
2529 tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
2530 tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
2530 failed = []
2531 failed = []
2531 for e in tmpExprs:
2532 for e in tmpExprs:
2532 try:
2533 try:
2533 tmpLoc = e.tryParse( instring, tmpLoc )
2534 tmpLoc = e.tryParse( instring, tmpLoc )
2534 except ParseException:
2535 except ParseException:
2535 failed.append(e)
2536 failed.append(e)
2536 else:
2537 else:
2537 matchOrder.append(e)
2538 matchOrder.append(e)
2538 if e in tmpReqd:
2539 if e in tmpReqd:
2539 tmpReqd.remove(e)
2540 tmpReqd.remove(e)
2540 elif e in tmpOpt:
2541 elif e in tmpOpt:
2541 tmpOpt.remove(e)
2542 tmpOpt.remove(e)
2542 if len(failed) == len(tmpExprs):
2543 if len(failed) == len(tmpExprs):
2543 keepMatching = False
2544 keepMatching = False
2544
2545
2545 if tmpReqd:
2546 if tmpReqd:
2546 missing = ", ".join( [ _ustr(e) for e in tmpReqd ] )
2547 missing = ", ".join( [ _ustr(e) for e in tmpReqd ] )
2547 raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
2548 raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
2548
2549
2549 # add any unmatched Optionals, in case they have default values defined
2550 # add any unmatched Optionals, in case they have default values defined
2550 matchOrder += list(e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt)
2551 matchOrder += list(e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt)
2551
2552
2552 resultlist = []
2553 resultlist = []
2553 for e in matchOrder:
2554 for e in matchOrder:
2554 loc,results = e._parse(instring,loc,doActions)
2555 loc,results = e._parse(instring,loc,doActions)
2555 resultlist.append(results)
2556 resultlist.append(results)
2556
2557
2557 finalResults = ParseResults([])
2558 finalResults = ParseResults([])
2558 for r in resultlist:
2559 for r in resultlist:
2559 dups = {}
2560 dups = {}
2560 for k in r.keys():
2561 for k in r.keys():
2561 if k in finalResults.keys():
2562 if k in finalResults.keys():
2562 tmp = ParseResults(finalResults[k])
2563 tmp = ParseResults(finalResults[k])
2563 tmp += ParseResults(r[k])
2564 tmp += ParseResults(r[k])
2564 dups[k] = tmp
2565 dups[k] = tmp
2565 finalResults += ParseResults(r)
2566 finalResults += ParseResults(r)
2566 for k,v in dups.items():
2567 for k,v in dups.iteritems():
2567 finalResults[k] = v
2568 finalResults[k] = v
2568 return loc, finalResults
2569 return loc, finalResults
2569
2570
2570 def __str__( self ):
2571 def __str__( self ):
2571 if hasattr(self,"name"):
2572 if hasattr(self,"name"):
2572 return self.name
2573 return self.name
2573
2574
2574 if self.strRepr is None:
2575 if self.strRepr is None:
2575 self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
2576 self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
2576
2577
2577 return self.strRepr
2578 return self.strRepr
2578
2579
2579 def checkRecursion( self, parseElementList ):
2580 def checkRecursion( self, parseElementList ):
2580 subRecCheckList = parseElementList[:] + [ self ]
2581 subRecCheckList = parseElementList[:] + [ self ]
2581 for e in self.exprs:
2582 for e in self.exprs:
2582 e.checkRecursion( subRecCheckList )
2583 e.checkRecursion( subRecCheckList )
2583
2584
2584
2585
2585 class ParseElementEnhance(ParserElement):
2586 class ParseElementEnhance(ParserElement):
2586 """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
2587 """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
2587 def __init__( self, expr, savelist=False ):
2588 def __init__( self, expr, savelist=False ):
2588 super(ParseElementEnhance,self).__init__(savelist)
2589 super(ParseElementEnhance,self).__init__(savelist)
2589 if isinstance( expr, basestring ):
2590 if isinstance( expr, basestring ):
2590 expr = Literal(expr)
2591 expr = Literal(expr)
2591 self.expr = expr
2592 self.expr = expr
2592 self.strRepr = None
2593 self.strRepr = None
2593 if expr is not None:
2594 if expr is not None:
2594 self.mayIndexError = expr.mayIndexError
2595 self.mayIndexError = expr.mayIndexError
2595 self.mayReturnEmpty = expr.mayReturnEmpty
2596 self.mayReturnEmpty = expr.mayReturnEmpty
2596 self.setWhitespaceChars( expr.whiteChars )
2597 self.setWhitespaceChars( expr.whiteChars )
2597 self.skipWhitespace = expr.skipWhitespace
2598 self.skipWhitespace = expr.skipWhitespace
2598 self.saveAsList = expr.saveAsList
2599 self.saveAsList = expr.saveAsList
2599 self.callPreparse = expr.callPreparse
2600 self.callPreparse = expr.callPreparse
2600 self.ignoreExprs.extend(expr.ignoreExprs)
2601 self.ignoreExprs.extend(expr.ignoreExprs)
2601
2602
2602 def parseImpl( self, instring, loc, doActions=True ):
2603 def parseImpl( self, instring, loc, doActions=True ):
2603 if self.expr is not None:
2604 if self.expr is not None:
2604 return self.expr._parse( instring, loc, doActions, callPreParse=False )
2605 return self.expr._parse( instring, loc, doActions, callPreParse=False )
2605 else:
2606 else:
2606 raise ParseException("",loc,self.errmsg,self)
2607 raise ParseException("",loc,self.errmsg,self)
2607
2608
2608 def leaveWhitespace( self ):
2609 def leaveWhitespace( self ):
2609 self.skipWhitespace = False
2610 self.skipWhitespace = False
2610 self.expr = self.expr.copy()
2611 self.expr = self.expr.copy()
2611 if self.expr is not None:
2612 if self.expr is not None:
2612 self.expr.leaveWhitespace()
2613 self.expr.leaveWhitespace()
2613 return self
2614 return self
2614
2615
2615 def ignore( self, other ):
2616 def ignore( self, other ):
2616 if isinstance( other, Suppress ):
2617 if isinstance( other, Suppress ):
2617 if other not in self.ignoreExprs:
2618 if other not in self.ignoreExprs:
2618 super( ParseElementEnhance, self).ignore( other )
2619 super( ParseElementEnhance, self).ignore( other )
2619 if self.expr is not None:
2620 if self.expr is not None:
2620 self.expr.ignore( self.ignoreExprs[-1] )
2621 self.expr.ignore( self.ignoreExprs[-1] )
2621 else:
2622 else:
2622 super( ParseElementEnhance, self).ignore( other )
2623 super( ParseElementEnhance, self).ignore( other )
2623 if self.expr is not None:
2624 if self.expr is not None:
2624 self.expr.ignore( self.ignoreExprs[-1] )
2625 self.expr.ignore( self.ignoreExprs[-1] )
2625 return self
2626 return self
2626
2627
2627 def streamline( self ):
2628 def streamline( self ):
2628 super(ParseElementEnhance,self).streamline()
2629 super(ParseElementEnhance,self).streamline()
2629 if self.expr is not None:
2630 if self.expr is not None:
2630 self.expr.streamline()
2631 self.expr.streamline()
2631 return self
2632 return self
2632
2633
2633 def checkRecursion( self, parseElementList ):
2634 def checkRecursion( self, parseElementList ):
2634 if self in parseElementList:
2635 if self in parseElementList:
2635 raise RecursiveGrammarException( parseElementList+[self] )
2636 raise RecursiveGrammarException( parseElementList+[self] )
2636 subRecCheckList = parseElementList[:] + [ self ]
2637 subRecCheckList = parseElementList[:] + [ self ]
2637 if self.expr is not None:
2638 if self.expr is not None:
2638 self.expr.checkRecursion( subRecCheckList )
2639 self.expr.checkRecursion( subRecCheckList )
2639
2640
2640 def validate( self, validateTrace=[] ):
2641 def validate( self, validateTrace=[] ):
2641 tmp = validateTrace[:]+[self]
2642 tmp = validateTrace[:]+[self]
2642 if self.expr is not None:
2643 if self.expr is not None:
2643 self.expr.validate(tmp)
2644 self.expr.validate(tmp)
2644 self.checkRecursion( [] )
2645 self.checkRecursion( [] )
2645
2646
2646 def __str__( self ):
2647 def __str__( self ):
2647 try:
2648 try:
2648 return super(ParseElementEnhance,self).__str__()
2649 return super(ParseElementEnhance,self).__str__()
2649 except:
2650 except:
2650 pass
2651 pass
2651
2652
2652 if self.strRepr is None and self.expr is not None:
2653 if self.strRepr is None and self.expr is not None:
2653 self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
2654 self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
2654 return self.strRepr
2655 return self.strRepr
2655
2656
2656
2657
2657 class FollowedBy(ParseElementEnhance):
2658 class FollowedBy(ParseElementEnhance):
2658 """Lookahead matching of the given parse expression. FollowedBy
2659 """Lookahead matching of the given parse expression. FollowedBy
2659 does *not* advance the parsing position within the input string, it only
2660 does *not* advance the parsing position within the input string, it only
2660 verifies that the specified parse expression matches at the current
2661 verifies that the specified parse expression matches at the current
2661 position. FollowedBy always returns a null token list."""
2662 position. FollowedBy always returns a null token list."""
2662 def __init__( self, expr ):
2663 def __init__( self, expr ):
2663 super(FollowedBy,self).__init__(expr)
2664 super(FollowedBy,self).__init__(expr)
2664 self.mayReturnEmpty = True
2665 self.mayReturnEmpty = True
2665
2666
2666 def parseImpl( self, instring, loc, doActions=True ):
2667 def parseImpl( self, instring, loc, doActions=True ):
2667 self.expr.tryParse( instring, loc )
2668 self.expr.tryParse( instring, loc )
2668 return loc, []
2669 return loc, []
2669
2670
2670
2671
2671 class NotAny(ParseElementEnhance):
2672 class NotAny(ParseElementEnhance):
2672 """Lookahead to disallow matching with the given parse expression. NotAny
2673 """Lookahead to disallow matching with the given parse expression. NotAny
2673 does *not* advance the parsing position within the input string, it only
2674 does *not* advance the parsing position within the input string, it only
2674 verifies that the specified parse expression does *not* match at the current
2675 verifies that the specified parse expression does *not* match at the current
2675 position. Also, NotAny does *not* skip over leading whitespace. NotAny
2676 position. Also, NotAny does *not* skip over leading whitespace. NotAny
2676 always returns a null token list. May be constructed using the '~' operator."""
2677 always returns a null token list. May be constructed using the '~' operator."""
2677 def __init__( self, expr ):
2678 def __init__( self, expr ):
2678 super(NotAny,self).__init__(expr)
2679 super(NotAny,self).__init__(expr)
2679 #~ self.leaveWhitespace()
2680 #~ self.leaveWhitespace()
2680 self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
2681 self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
2681 self.mayReturnEmpty = True
2682 self.mayReturnEmpty = True
2682 self.errmsg = "Found unwanted token, "+_ustr(self.expr)
2683 self.errmsg = "Found unwanted token, "+_ustr(self.expr)
2683 #self.myException = ParseException("",0,self.errmsg,self)
2684 #self.myException = ParseException("",0,self.errmsg,self)
2684
2685
2685 def parseImpl( self, instring, loc, doActions=True ):
2686 def parseImpl( self, instring, loc, doActions=True ):
2686 try:
2687 try:
2687 self.expr.tryParse( instring, loc )
2688 self.expr.tryParse( instring, loc )
2688 except (ParseException,IndexError):
2689 except (ParseException,IndexError):
2689 pass
2690 pass
2690 else:
2691 else:
2691 #~ raise ParseException(instring, loc, self.errmsg )
2692 #~ raise ParseException(instring, loc, self.errmsg )
2692 exc = self.myException
2693 exc = self.myException
2693 exc.loc = loc
2694 exc.loc = loc
2694 exc.pstr = instring
2695 exc.pstr = instring
2695 raise exc
2696 raise exc
2696 return loc, []
2697 return loc, []
2697
2698
2698 def __str__( self ):
2699 def __str__( self ):
2699 if hasattr(self,"name"):
2700 if hasattr(self,"name"):
2700 return self.name
2701 return self.name
2701
2702
2702 if self.strRepr is None:
2703 if self.strRepr is None:
2703 self.strRepr = "~{" + _ustr(self.expr) + "}"
2704 self.strRepr = "~{" + _ustr(self.expr) + "}"
2704
2705
2705 return self.strRepr
2706 return self.strRepr
2706
2707
2707
2708
2708 class ZeroOrMore(ParseElementEnhance):
2709 class ZeroOrMore(ParseElementEnhance):
2709 """Optional repetition of zero or more of the given expression."""
2710 """Optional repetition of zero or more of the given expression."""
2710 def __init__( self, expr ):
2711 def __init__( self, expr ):
2711 super(ZeroOrMore,self).__init__(expr)
2712 super(ZeroOrMore,self).__init__(expr)
2712 self.mayReturnEmpty = True
2713 self.mayReturnEmpty = True
2713
2714
2714 def parseImpl( self, instring, loc, doActions=True ):
2715 def parseImpl( self, instring, loc, doActions=True ):
2715 tokens = []
2716 tokens = []
2716 try:
2717 try:
2717 loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
2718 loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
2718 hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
2719 hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
2719 while 1:
2720 while 1:
2720 if hasIgnoreExprs:
2721 if hasIgnoreExprs:
2721 preloc = self._skipIgnorables( instring, loc )
2722 preloc = self._skipIgnorables( instring, loc )
2722 else:
2723 else:
2723 preloc = loc
2724 preloc = loc
2724 loc, tmptokens = self.expr._parse( instring, preloc, doActions )
2725 loc, tmptokens = self.expr._parse( instring, preloc, doActions )
2725 if tmptokens or tmptokens.keys():
2726 if tmptokens or tmptokens.keys():
2726 tokens += tmptokens
2727 tokens += tmptokens
2727 except (ParseException,IndexError):
2728 except (ParseException,IndexError):
2728 pass
2729 pass
2729
2730
2730 return loc, tokens
2731 return loc, tokens
2731
2732
2732 def __str__( self ):
2733 def __str__( self ):
2733 if hasattr(self,"name"):
2734 if hasattr(self,"name"):
2734 return self.name
2735 return self.name
2735
2736
2736 if self.strRepr is None:
2737 if self.strRepr is None:
2737 self.strRepr = "[" + _ustr(self.expr) + "]..."
2738 self.strRepr = "[" + _ustr(self.expr) + "]..."
2738
2739
2739 return self.strRepr
2740 return self.strRepr
2740
2741
2741 def setResultsName( self, name, listAllMatches=False ):
2742 def setResultsName( self, name, listAllMatches=False ):
2742 ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches)
2743 ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches)
2743 ret.saveAsList = True
2744 ret.saveAsList = True
2744 return ret
2745 return ret
2745
2746
2746
2747
2747 class OneOrMore(ParseElementEnhance):
2748 class OneOrMore(ParseElementEnhance):
2748 """Repetition of one or more of the given expression."""
2749 """Repetition of one or more of the given expression."""
2749 def parseImpl( self, instring, loc, doActions=True ):
2750 def parseImpl( self, instring, loc, doActions=True ):
2750 # must be at least one
2751 # must be at least one
2751 loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
2752 loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
2752 try:
2753 try:
2753 hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
2754 hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
2754 while 1:
2755 while 1:
2755 if hasIgnoreExprs:
2756 if hasIgnoreExprs:
2756 preloc = self._skipIgnorables( instring, loc )
2757 preloc = self._skipIgnorables( instring, loc )
2757 else:
2758 else:
2758 preloc = loc
2759 preloc = loc
2759 loc, tmptokens = self.expr._parse( instring, preloc, doActions )
2760 loc, tmptokens = self.expr._parse( instring, preloc, doActions )
2760 if tmptokens or tmptokens.keys():
2761 if tmptokens or tmptokens.keys():
2761 tokens += tmptokens
2762 tokens += tmptokens
2762 except (ParseException,IndexError):
2763 except (ParseException,IndexError):
2763 pass
2764 pass
2764
2765
2765 return loc, tokens
2766 return loc, tokens
2766
2767
2767 def __str__( self ):
2768 def __str__( self ):
2768 if hasattr(self,"name"):
2769 if hasattr(self,"name"):
2769 return self.name
2770 return self.name
2770
2771
2771 if self.strRepr is None:
2772 if self.strRepr is None:
2772 self.strRepr = "{" + _ustr(self.expr) + "}..."
2773 self.strRepr = "{" + _ustr(self.expr) + "}..."
2773
2774
2774 return self.strRepr
2775 return self.strRepr
2775
2776
2776 def setResultsName( self, name, listAllMatches=False ):
2777 def setResultsName( self, name, listAllMatches=False ):
2777 ret = super(OneOrMore,self).setResultsName(name,listAllMatches)
2778 ret = super(OneOrMore,self).setResultsName(name,listAllMatches)
2778 ret.saveAsList = True
2779 ret.saveAsList = True
2779 return ret
2780 return ret
2780
2781
2781 class _NullToken(object):
2782 class _NullToken(object):
2782 def __bool__(self):
2783 def __bool__(self):
2783 return False
2784 return False
2784 __nonzero__ = __bool__
2785 __nonzero__ = __bool__
2785 def __str__(self):
2786 def __str__(self):
2786 return ""
2787 return ""
2787
2788
2788 _optionalNotMatched = _NullToken()
2789 _optionalNotMatched = _NullToken()
2789 class Optional(ParseElementEnhance):
2790 class Optional(ParseElementEnhance):
2790 """Optional matching of the given expression.
2791 """Optional matching of the given expression.
2791 A default return string can also be specified, if the optional expression
2792 A default return string can also be specified, if the optional expression
2792 is not found.
2793 is not found.
2793 """
2794 """
2794 def __init__( self, exprs, default=_optionalNotMatched ):
2795 def __init__( self, exprs, default=_optionalNotMatched ):
2795 super(Optional,self).__init__( exprs, savelist=False )
2796 super(Optional,self).__init__( exprs, savelist=False )
2796 self.defaultValue = default
2797 self.defaultValue = default
2797 self.mayReturnEmpty = True
2798 self.mayReturnEmpty = True
2798
2799
2799 def parseImpl( self, instring, loc, doActions=True ):
2800 def parseImpl( self, instring, loc, doActions=True ):
2800 try:
2801 try:
2801 loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
2802 loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
2802 except (ParseException,IndexError):
2803 except (ParseException,IndexError):
2803 if self.defaultValue is not _optionalNotMatched:
2804 if self.defaultValue is not _optionalNotMatched:
2804 if self.expr.resultsName:
2805 if self.expr.resultsName:
2805 tokens = ParseResults([ self.defaultValue ])
2806 tokens = ParseResults([ self.defaultValue ])
2806 tokens[self.expr.resultsName] = self.defaultValue
2807 tokens[self.expr.resultsName] = self.defaultValue
2807 else:
2808 else:
2808 tokens = [ self.defaultValue ]
2809 tokens = [ self.defaultValue ]
2809 else:
2810 else:
2810 tokens = []
2811 tokens = []
2811 return loc, tokens
2812 return loc, tokens
2812
2813
2813 def __str__( self ):
2814 def __str__( self ):
2814 if hasattr(self,"name"):
2815 if hasattr(self,"name"):
2815 return self.name
2816 return self.name
2816
2817
2817 if self.strRepr is None:
2818 if self.strRepr is None:
2818 self.strRepr = "[" + _ustr(self.expr) + "]"
2819 self.strRepr = "[" + _ustr(self.expr) + "]"
2819
2820
2820 return self.strRepr
2821 return self.strRepr
2821
2822
2822
2823
2823 class SkipTo(ParseElementEnhance):
2824 class SkipTo(ParseElementEnhance):
2824 """Token for skipping over all undefined text until the matched expression is found.
2825 """Token for skipping over all undefined text until the matched expression is found.
2825 If include is set to true, the matched expression is also parsed (the skipped text
2826 If include is set to true, the matched expression is also parsed (the skipped text
2826 and matched expression are returned as a 2-element list). The ignore
2827 and matched expression are returned as a 2-element list). The ignore
2827 argument is used to define grammars (typically quoted strings and comments) that
2828 argument is used to define grammars (typically quoted strings and comments) that
2828 might contain false matches.
2829 might contain false matches.
2829 """
2830 """
2830 def __init__( self, other, include=False, ignore=None, failOn=None ):
2831 def __init__( self, other, include=False, ignore=None, failOn=None ):
2831 super( SkipTo, self ).__init__( other )
2832 super( SkipTo, self ).__init__( other )
2832 self.ignoreExpr = ignore
2833 self.ignoreExpr = ignore
2833 self.mayReturnEmpty = True
2834 self.mayReturnEmpty = True
2834 self.mayIndexError = False
2835 self.mayIndexError = False
2835 self.includeMatch = include
2836 self.includeMatch = include
2836 self.asList = False
2837 self.asList = False
2837 if failOn is not None and isinstance(failOn, basestring):
2838 if failOn is not None and isinstance(failOn, basestring):
2838 self.failOn = Literal(failOn)
2839 self.failOn = Literal(failOn)
2839 else:
2840 else:
2840 self.failOn = failOn
2841 self.failOn = failOn
2841 self.errmsg = "No match found for "+_ustr(self.expr)
2842 self.errmsg = "No match found for "+_ustr(self.expr)
2842 #self.myException = ParseException("",0,self.errmsg,self)
2843 #self.myException = ParseException("",0,self.errmsg,self)
2843
2844
2844 def parseImpl( self, instring, loc, doActions=True ):
2845 def parseImpl( self, instring, loc, doActions=True ):
2845 startLoc = loc
2846 startLoc = loc
2846 instrlen = len(instring)
2847 instrlen = len(instring)
2847 expr = self.expr
2848 expr = self.expr
2848 failParse = False
2849 failParse = False
2849 while loc <= instrlen:
2850 while loc <= instrlen:
2850 try:
2851 try:
2851 if self.failOn:
2852 if self.failOn:
2852 try:
2853 try:
2853 self.failOn.tryParse(instring, loc)
2854 self.failOn.tryParse(instring, loc)
2854 except ParseBaseException:
2855 except ParseBaseException:
2855 pass
2856 pass
2856 else:
2857 else:
2857 failParse = True
2858 failParse = True
2858 raise ParseException(instring, loc, "Found expression " + str(self.failOn))
2859 raise ParseException(instring, loc, "Found expression " + str(self.failOn))
2859 failParse = False
2860 failParse = False
2860 if self.ignoreExpr is not None:
2861 if self.ignoreExpr is not None:
2861 while 1:
2862 while 1:
2862 try:
2863 try:
2863 loc = self.ignoreExpr.tryParse(instring,loc)
2864 loc = self.ignoreExpr.tryParse(instring,loc)
2864 print "found ignoreExpr, advance to", loc
2865 print "found ignoreExpr, advance to", loc
2865 except ParseBaseException:
2866 except ParseBaseException:
2866 break
2867 break
2867 expr._parse( instring, loc, doActions=False, callPreParse=False )
2868 expr._parse( instring, loc, doActions=False, callPreParse=False )
2868 skipText = instring[startLoc:loc]
2869 skipText = instring[startLoc:loc]
2869 if self.includeMatch:
2870 if self.includeMatch:
2870 loc,mat = expr._parse(instring,loc,doActions,callPreParse=False)
2871 loc,mat = expr._parse(instring,loc,doActions,callPreParse=False)
2871 if mat:
2872 if mat:
2872 skipRes = ParseResults( skipText )
2873 skipRes = ParseResults( skipText )
2873 skipRes += mat
2874 skipRes += mat
2874 return loc, [ skipRes ]
2875 return loc, [ skipRes ]
2875 else:
2876 else:
2876 return loc, [ skipText ]
2877 return loc, [ skipText ]
2877 else:
2878 else:
2878 return loc, [ skipText ]
2879 return loc, [ skipText ]
2879 except (ParseException,IndexError):
2880 except (ParseException,IndexError):
2880 if failParse:
2881 if failParse:
2881 raise
2882 raise
2882 else:
2883 else:
2883 loc += 1
2884 loc += 1
2884 exc = self.myException
2885 exc = self.myException
2885 exc.loc = loc
2886 exc.loc = loc
2886 exc.pstr = instring
2887 exc.pstr = instring
2887 raise exc
2888 raise exc
2888
2889
2889 class Forward(ParseElementEnhance):
2890 class Forward(ParseElementEnhance):
2890 """Forward declaration of an expression to be defined later -
2891 """Forward declaration of an expression to be defined later -
2891 used for recursive grammars, such as algebraic infix notation.
2892 used for recursive grammars, such as algebraic infix notation.
2892 When the expression is known, it is assigned to the Forward variable using the '<<' operator.
2893 When the expression is known, it is assigned to the Forward variable using the '<<' operator.
2893
2894
2894 Note: take care when assigning to Forward not to overlook precedence of operators.
2895 Note: take care when assigning to Forward not to overlook precedence of operators.
2895 Specifically, '|' has a lower precedence than '<<', so that::
2896 Specifically, '|' has a lower precedence than '<<', so that::
2896 fwdExpr << a | b | c
2897 fwdExpr << a | b | c
2897 will actually be evaluated as::
2898 will actually be evaluated as::
2898 (fwdExpr << a) | b | c
2899 (fwdExpr << a) | b | c
2899 thereby leaving b and c out as parseable alternatives. It is recommended that you
2900 thereby leaving b and c out as parseable alternatives. It is recommended that you
2900 explicitly group the values inserted into the Forward::
2901 explicitly group the values inserted into the Forward::
2901 fwdExpr << (a | b | c)
2902 fwdExpr << (a | b | c)
2902 """
2903 """
2903 def __init__( self, other=None ):
2904 def __init__( self, other=None ):
2904 super(Forward,self).__init__( other, savelist=False )
2905 super(Forward,self).__init__( other, savelist=False )
2905
2906
2906 def __lshift__( self, other ):
2907 def __lshift__( self, other ):
2907 if isinstance( other, basestring ):
2908 if isinstance( other, basestring ):
2908 other = Literal(other)
2909 other = Literal(other)
2909 self.expr = other
2910 self.expr = other
2910 self.mayReturnEmpty = other.mayReturnEmpty
2911 self.mayReturnEmpty = other.mayReturnEmpty
2911 self.strRepr = None
2912 self.strRepr = None
2912 self.mayIndexError = self.expr.mayIndexError
2913 self.mayIndexError = self.expr.mayIndexError
2913 self.mayReturnEmpty = self.expr.mayReturnEmpty
2914 self.mayReturnEmpty = self.expr.mayReturnEmpty
2914 self.setWhitespaceChars( self.expr.whiteChars )
2915 self.setWhitespaceChars( self.expr.whiteChars )
2915 self.skipWhitespace = self.expr.skipWhitespace
2916 self.skipWhitespace = self.expr.skipWhitespace
2916 self.saveAsList = self.expr.saveAsList
2917 self.saveAsList = self.expr.saveAsList
2917 self.ignoreExprs.extend(self.expr.ignoreExprs)
2918 self.ignoreExprs.extend(self.expr.ignoreExprs)
2918 return None
2919 return None
2919
2920
2920 def leaveWhitespace( self ):
2921 def leaveWhitespace( self ):
2921 self.skipWhitespace = False
2922 self.skipWhitespace = False
2922 return self
2923 return self
2923
2924
2924 def streamline( self ):
2925 def streamline( self ):
2925 if not self.streamlined:
2926 if not self.streamlined:
2926 self.streamlined = True
2927 self.streamlined = True
2927 if self.expr is not None:
2928 if self.expr is not None:
2928 self.expr.streamline()
2929 self.expr.streamline()
2929 return self
2930 return self
2930
2931
2931 def validate( self, validateTrace=[] ):
2932 def validate( self, validateTrace=[] ):
2932 if self not in validateTrace:
2933 if self not in validateTrace:
2933 tmp = validateTrace[:]+[self]
2934 tmp = validateTrace[:]+[self]
2934 if self.expr is not None:
2935 if self.expr is not None:
2935 self.expr.validate(tmp)
2936 self.expr.validate(tmp)
2936 self.checkRecursion([])
2937 self.checkRecursion([])
2937
2938
2938 def __str__( self ):
2939 def __str__( self ):
2939 if hasattr(self,"name"):
2940 if hasattr(self,"name"):
2940 return self.name
2941 return self.name
2941
2942
2942 self._revertClass = self.__class__
2943 self._revertClass = self.__class__
2943 self.__class__ = _ForwardNoRecurse
2944 self.__class__ = _ForwardNoRecurse
2944 try:
2945 try:
2945 if self.expr is not None:
2946 if self.expr is not None:
2946 retString = _ustr(self.expr)
2947 retString = _ustr(self.expr)
2947 else:
2948 else:
2948 retString = "None"
2949 retString = "None"
2949 finally:
2950 finally:
2950 self.__class__ = self._revertClass
2951 self.__class__ = self._revertClass
2951 return self.__class__.__name__ + ": " + retString
2952 return self.__class__.__name__ + ": " + retString
2952
2953
2953 def copy(self):
2954 def copy(self):
2954 if self.expr is not None:
2955 if self.expr is not None:
2955 return super(Forward,self).copy()
2956 return super(Forward,self).copy()
2956 else:
2957 else:
2957 ret = Forward()
2958 ret = Forward()
2958 ret << self
2959 ret << self
2959 return ret
2960 return ret
2960
2961
2961 class _ForwardNoRecurse(Forward):
2962 class _ForwardNoRecurse(Forward):
2962 def __str__( self ):
2963 def __str__( self ):
2963 return "..."
2964 return "..."
2964
2965
2965 class TokenConverter(ParseElementEnhance):
2966 class TokenConverter(ParseElementEnhance):
2966 """Abstract subclass of ParseExpression, for converting parsed results."""
2967 """Abstract subclass of ParseExpression, for converting parsed results."""
2967 def __init__( self, expr, savelist=False ):
2968 def __init__( self, expr, savelist=False ):
2968 super(TokenConverter,self).__init__( expr )#, savelist )
2969 super(TokenConverter,self).__init__( expr )#, savelist )
2969 self.saveAsList = False
2970 self.saveAsList = False
2970
2971
2971 class Upcase(TokenConverter):
2972 class Upcase(TokenConverter):
2972 """Converter to upper case all matching tokens."""
2973 """Converter to upper case all matching tokens."""
2973 def __init__(self, *args):
2974 def __init__(self, *args):
2974 super(Upcase,self).__init__(*args)
2975 super(Upcase,self).__init__(*args)
2975 warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead",
2976 warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead",
2976 DeprecationWarning,stacklevel=2)
2977 DeprecationWarning,stacklevel=2)
2977
2978
2978 def postParse( self, instring, loc, tokenlist ):
2979 def postParse( self, instring, loc, tokenlist ):
2979 return list(map( string.upper, tokenlist ))
2980 return list(map( string.upper, tokenlist ))
2980
2981
2981
2982
2982 class Combine(TokenConverter):
2983 class Combine(TokenConverter):
2983 """Converter to concatenate all matching tokens to a single string.
2984 """Converter to concatenate all matching tokens to a single string.
2984 By default, the matching patterns must also be contiguous in the input string;
2985 By default, the matching patterns must also be contiguous in the input string;
2985 this can be disabled by specifying 'adjacent=False' in the constructor.
2986 this can be disabled by specifying 'adjacent=False' in the constructor.
2986 """
2987 """
2987 def __init__( self, expr, joinString="", adjacent=True ):
2988 def __init__( self, expr, joinString="", adjacent=True ):
2988 super(Combine,self).__init__( expr )
2989 super(Combine,self).__init__( expr )
2989 # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
2990 # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
2990 if adjacent:
2991 if adjacent:
2991 self.leaveWhitespace()
2992 self.leaveWhitespace()
2992 self.adjacent = adjacent
2993 self.adjacent = adjacent
2993 self.skipWhitespace = True
2994 self.skipWhitespace = True
2994 self.joinString = joinString
2995 self.joinString = joinString
2995
2996
2996 def ignore( self, other ):
2997 def ignore( self, other ):
2997 if self.adjacent:
2998 if self.adjacent:
2998 ParserElement.ignore(self, other)
2999 ParserElement.ignore(self, other)
2999 else:
3000 else:
3000 super( Combine, self).ignore( other )
3001 super( Combine, self).ignore( other )
3001 return self
3002 return self
3002
3003
3003 def postParse( self, instring, loc, tokenlist ):
3004 def postParse( self, instring, loc, tokenlist ):
3004 retToks = tokenlist.copy()
3005 retToks = tokenlist.copy()
3005 del retToks[:]
3006 del retToks[:]
3006 retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
3007 retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
3007
3008
3008 if self.resultsName and len(retToks.keys())>0:
3009 if self.resultsName and len(retToks.keys())>0:
3009 return [ retToks ]
3010 return [ retToks ]
3010 else:
3011 else:
3011 return retToks
3012 return retToks
3012
3013
3013 class Group(TokenConverter):
3014 class Group(TokenConverter):
3014 """Converter to return the matched tokens as a list - useful for returning tokens of ZeroOrMore and OneOrMore expressions."""
3015 """Converter to return the matched tokens as a list - useful for returning tokens of ZeroOrMore and OneOrMore expressions."""
3015 def __init__( self, expr ):
3016 def __init__( self, expr ):
3016 super(Group,self).__init__( expr )
3017 super(Group,self).__init__( expr )
3017 self.saveAsList = True
3018 self.saveAsList = True
3018
3019
3019 def postParse( self, instring, loc, tokenlist ):
3020 def postParse( self, instring, loc, tokenlist ):
3020 return [ tokenlist ]
3021 return [ tokenlist ]
3021
3022
3022 class Dict(TokenConverter):
3023 class Dict(TokenConverter):
3023 """Converter to return a repetitive expression as a list, but also as a dictionary.
3024 """Converter to return a repetitive expression as a list, but also as a dictionary.
3024 Each element can also be referenced using the first token in the expression as its key.
3025 Each element can also be referenced using the first token in the expression as its key.
3025 Useful for tabular report scraping when the first column can be used as a item key.
3026 Useful for tabular report scraping when the first column can be used as a item key.
3026 """
3027 """
3027 def __init__( self, exprs ):
3028 def __init__( self, exprs ):
3028 super(Dict,self).__init__( exprs )
3029 super(Dict,self).__init__( exprs )
3029 self.saveAsList = True
3030 self.saveAsList = True
3030
3031
3031 def postParse( self, instring, loc, tokenlist ):
3032 def postParse( self, instring, loc, tokenlist ):
3032 for i,tok in enumerate(tokenlist):
3033 for i,tok in enumerate(tokenlist):
3033 if len(tok) == 0:
3034 if len(tok) == 0:
3034 continue
3035 continue
3035 ikey = tok[0]
3036 ikey = tok[0]
3036 if isinstance(ikey,int):
3037 if isinstance(ikey,int):
3037 ikey = _ustr(tok[0]).strip()
3038 ikey = _ustr(tok[0]).strip()
3038 if len(tok)==1:
3039 if len(tok)==1:
3039 tokenlist[ikey] = _ParseResultsWithOffset("",i)
3040 tokenlist[ikey] = _ParseResultsWithOffset("",i)
3040 elif len(tok)==2 and not isinstance(tok[1],ParseResults):
3041 elif len(tok)==2 and not isinstance(tok[1],ParseResults):
3041 tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
3042 tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
3042 else:
3043 else:
3043 dictvalue = tok.copy() #ParseResults(i)
3044 dictvalue = tok.copy() #ParseResults(i)
3044 del dictvalue[0]
3045 del dictvalue[0]
3045 if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()):
3046 if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()):
3046 tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
3047 tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
3047 else:
3048 else:
3048 tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
3049 tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
3049
3050
3050 if self.resultsName:
3051 if self.resultsName:
3051 return [ tokenlist ]
3052 return [ tokenlist ]
3052 else:
3053 else:
3053 return tokenlist
3054 return tokenlist
3054
3055
3055
3056
3056 class Suppress(TokenConverter):
3057 class Suppress(TokenConverter):
3057 """Converter for ignoring the results of a parsed expression."""
3058 """Converter for ignoring the results of a parsed expression."""
3058 def postParse( self, instring, loc, tokenlist ):
3059 def postParse( self, instring, loc, tokenlist ):
3059 return []
3060 return []
3060
3061
3061 def suppress( self ):
3062 def suppress( self ):
3062 return self
3063 return self
3063
3064
3064
3065
3065 class OnlyOnce(object):
3066 class OnlyOnce(object):
3066 """Wrapper for parse actions, to ensure they are only called once."""
3067 """Wrapper for parse actions, to ensure they are only called once."""
3067 def __init__(self, methodCall):
3068 def __init__(self, methodCall):
3068 self.callable = ParserElement._normalizeParseActionArgs(methodCall)
3069 self.callable = ParserElement._normalizeParseActionArgs(methodCall)
3069 self.called = False
3070 self.called = False
3070 def __call__(self,s,l,t):
3071 def __call__(self,s,l,t):
3071 if not self.called:
3072 if not self.called:
3072 results = self.callable(s,l,t)
3073 results = self.callable(s,l,t)
3073 self.called = True
3074 self.called = True
3074 return results
3075 return results
3075 raise ParseException(s,l,"")
3076 raise ParseException(s,l,"")
3076 def reset(self):
3077 def reset(self):
3077 self.called = False
3078 self.called = False
3078
3079
3079 def traceParseAction(f):
3080 def traceParseAction(f):
3080 """Decorator for debugging parse actions."""
3081 """Decorator for debugging parse actions."""
3081 f = ParserElement._normalizeParseActionArgs(f)
3082 f = ParserElement._normalizeParseActionArgs(f)
3082 def z(*paArgs):
3083 def z(*paArgs):
3083 thisFunc = f.func_name
3084 thisFunc = f.func_name
3084 s,l,t = paArgs[-3:]
3085 s,l,t = paArgs[-3:]
3085 if len(paArgs)>3:
3086 if len(paArgs)>3:
3086 thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
3087 thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
3087 sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) )
3088 sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) )
3088 try:
3089 try:
3089 ret = f(*paArgs)
3090 ret = f(*paArgs)
3090 except Exception, exc:
3091 except Exception, exc:
3091 sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )
3092 sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )
3092 raise
3093 raise
3093 sys.stderr.write( "<<leaving %s (ret: %s)\n" % (thisFunc,ret) )
3094 sys.stderr.write( "<<leaving %s (ret: %s)\n" % (thisFunc,ret) )
3094 return ret
3095 return ret
3095 try:
3096 try:
3096 z.__name__ = f.__name__
3097 z.__name__ = f.__name__
3097 except AttributeError:
3098 except AttributeError:
3098 pass
3099 pass
3099 return z
3100 return z
3100
3101
3101 #
3102 #
3102 # global helpers
3103 # global helpers
3103 #
3104 #
3104 def delimitedList( expr, delim=",", combine=False ):
3105 def delimitedList( expr, delim=",", combine=False ):
3105 """Helper to define a delimited list of expressions - the delimiter defaults to ','.
3106 """Helper to define a delimited list of expressions - the delimiter defaults to ','.
3106 By default, the list elements and delimiters can have intervening whitespace, and
3107 By default, the list elements and delimiters can have intervening whitespace, and
3107 comments, but this can be overridden by passing 'combine=True' in the constructor.
3108 comments, but this can be overridden by passing 'combine=True' in the constructor.
3108 If combine is set to True, the matching tokens are returned as a single token
3109 If combine is set to True, the matching tokens are returned as a single token
3109 string, with the delimiters included; otherwise, the matching tokens are returned
3110 string, with the delimiters included; otherwise, the matching tokens are returned
3110 as a list of tokens, with the delimiters suppressed.
3111 as a list of tokens, with the delimiters suppressed.
3111 """
3112 """
3112 dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
3113 dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
3113 if combine:
3114 if combine:
3114 return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
3115 return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
3115 else:
3116 else:
3116 return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
3117 return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
3117
3118
3118 def countedArray( expr ):
3119 def countedArray( expr ):
3119 """Helper to define a counted list of expressions.
3120 """Helper to define a counted list of expressions.
3120 This helper defines a pattern of the form::
3121 This helper defines a pattern of the form::
3121 integer expr expr expr...
3122 integer expr expr expr...
3122 where the leading integer tells how many expr expressions follow.
3123 where the leading integer tells how many expr expressions follow.
3123 The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
3124 The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
3124 """
3125 """
3125 arrayExpr = Forward()
3126 arrayExpr = Forward()
3126 def countFieldParseAction(s,l,t):
3127 def countFieldParseAction(s,l,t):
3127 n = int(t[0])
3128 n = int(t[0])
3128 arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
3129 arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
3129 return []
3130 return []
3130 return ( Word(nums).setName("arrayLen").setParseAction(countFieldParseAction, callDuringTry=True) + arrayExpr )
3131 return ( Word(nums).setName("arrayLen").setParseAction(countFieldParseAction, callDuringTry=True) + arrayExpr )
3131
3132
3132 def _flatten(L):
3133 def _flatten(L):
3133 if type(L) is not list: return [L]
3134 if type(L) is not list: return [L]
3134 if L == []: return L
3135 if L == []: return L
3135 return _flatten(L[0]) + _flatten(L[1:])
3136 return _flatten(L[0]) + _flatten(L[1:])
3136
3137
3137 def matchPreviousLiteral(expr):
3138 def matchPreviousLiteral(expr):
3138 """Helper to define an expression that is indirectly defined from
3139 """Helper to define an expression that is indirectly defined from
3139 the tokens matched in a previous expression, that is, it looks
3140 the tokens matched in a previous expression, that is, it looks
3140 for a 'repeat' of a previous expression. For example::
3141 for a 'repeat' of a previous expression. For example::
3141 first = Word(nums)
3142 first = Word(nums)
3142 second = matchPreviousLiteral(first)
3143 second = matchPreviousLiteral(first)
3143 matchExpr = first + ":" + second
3144 matchExpr = first + ":" + second
3144 will match "1:1", but not "1:2". Because this matches a
3145 will match "1:1", but not "1:2". Because this matches a
3145 previous literal, will also match the leading "1:1" in "1:10".
3146 previous literal, will also match the leading "1:1" in "1:10".
3146 If this is not desired, use matchPreviousExpr.
3147 If this is not desired, use matchPreviousExpr.
3147 Do *not* use with packrat parsing enabled.
3148 Do *not* use with packrat parsing enabled.
3148 """
3149 """
3149 rep = Forward()
3150 rep = Forward()
3150 def copyTokenToRepeater(s,l,t):
3151 def copyTokenToRepeater(s,l,t):
3151 if t:
3152 if t:
3152 if len(t) == 1:
3153 if len(t) == 1:
3153 rep << t[0]
3154 rep << t[0]
3154 else:
3155 else:
3155 # flatten t tokens
3156 # flatten t tokens
3156 tflat = _flatten(t.asList())
3157 tflat = _flatten(t.asList())
3157 rep << And( [ Literal(tt) for tt in tflat ] )
3158 rep << And( [ Literal(tt) for tt in tflat ] )
3158 else:
3159 else:
3159 rep << Empty()
3160 rep << Empty()
3160 expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
3161 expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
3161 return rep
3162 return rep
3162
3163
3163 def matchPreviousExpr(expr):
3164 def matchPreviousExpr(expr):
3164 """Helper to define an expression that is indirectly defined from
3165 """Helper to define an expression that is indirectly defined from
3165 the tokens matched in a previous expression, that is, it looks
3166 the tokens matched in a previous expression, that is, it looks
3166 for a 'repeat' of a previous expression. For example::
3167 for a 'repeat' of a previous expression. For example::
3167 first = Word(nums)
3168 first = Word(nums)
3168 second = matchPreviousExpr(first)
3169 second = matchPreviousExpr(first)
3169 matchExpr = first + ":" + second
3170 matchExpr = first + ":" + second
3170 will match "1:1", but not "1:2". Because this matches by
3171 will match "1:1", but not "1:2". Because this matches by
3171 expressions, will *not* match the leading "1:1" in "1:10";
3172 expressions, will *not* match the leading "1:1" in "1:10";
3172 the expressions are evaluated first, and then compared, so
3173 the expressions are evaluated first, and then compared, so
3173 "1" is compared with "10".
3174 "1" is compared with "10".
3174 Do *not* use with packrat parsing enabled.
3175 Do *not* use with packrat parsing enabled.
3175 """
3176 """
3176 rep = Forward()
3177 rep = Forward()
3177 e2 = expr.copy()
3178 e2 = expr.copy()
3178 rep << e2
3179 rep << e2
3179 def copyTokenToRepeater(s,l,t):
3180 def copyTokenToRepeater(s,l,t):
3180 matchTokens = _flatten(t.asList())
3181 matchTokens = _flatten(t.asList())
3181 def mustMatchTheseTokens(s,l,t):
3182 def mustMatchTheseTokens(s,l,t):
3182 theseTokens = _flatten(t.asList())
3183 theseTokens = _flatten(t.asList())
3183 if theseTokens != matchTokens:
3184 if theseTokens != matchTokens:
3184 raise ParseException("",0,"")
3185 raise ParseException("",0,"")
3185 rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
3186 rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
3186 expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
3187 expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
3187 return rep
3188 return rep
3188
3189
3189 def _escapeRegexRangeChars(s):
3190 def _escapeRegexRangeChars(s):
3190 #~ escape these chars: ^-]
3191 #~ escape these chars: ^-]
3191 for c in r"\^-]":
3192 for c in r"\^-]":
3192 s = s.replace(c,_bslash+c)
3193 s = s.replace(c,_bslash+c)
3193 s = s.replace("\n",r"\n")
3194 s = s.replace("\n",r"\n")
3194 s = s.replace("\t",r"\t")
3195 s = s.replace("\t",r"\t")
3195 return _ustr(s)
3196 return _ustr(s)
3196
3197
3197 def oneOf( strs, caseless=False, useRegex=True ):
3198 def oneOf( strs, caseless=False, useRegex=True ):
3198 """Helper to quickly define a set of alternative Literals, and makes sure to do
3199 """Helper to quickly define a set of alternative Literals, and makes sure to do
3199 longest-first testing when there is a conflict, regardless of the input order,
3200 longest-first testing when there is a conflict, regardless of the input order,
3200 but returns a MatchFirst for best performance.
3201 but returns a MatchFirst for best performance.
3201
3202
3202 Parameters:
3203 Parameters:
3203 - strs - a string of space-delimited literals, or a list of string literals
3204 - strs - a string of space-delimited literals, or a list of string literals
3204 - caseless - (default=False) - treat all literals as caseless
3205 - caseless - (default=False) - treat all literals as caseless
3205 - useRegex - (default=True) - as an optimization, will generate a Regex
3206 - useRegex - (default=True) - as an optimization, will generate a Regex
3206 object; otherwise, will generate a MatchFirst object (if caseless=True, or
3207 object; otherwise, will generate a MatchFirst object (if caseless=True, or
3207 if creating a Regex raises an exception)
3208 if creating a Regex raises an exception)
3208 """
3209 """
3209 if caseless:
3210 if caseless:
3210 isequal = ( lambda a,b: a.upper() == b.upper() )
3211 isequal = ( lambda a,b: a.upper() == b.upper() )
3211 masks = ( lambda a,b: b.upper().startswith(a.upper()) )
3212 masks = ( lambda a,b: b.upper().startswith(a.upper()) )
3212 parseElementClass = CaselessLiteral
3213 parseElementClass = CaselessLiteral
3213 else:
3214 else:
3214 isequal = ( lambda a,b: a == b )
3215 isequal = ( lambda a,b: a == b )
3215 masks = ( lambda a,b: b.startswith(a) )
3216 masks = ( lambda a,b: b.startswith(a) )
3216 parseElementClass = Literal
3217 parseElementClass = Literal
3217
3218
3218 if isinstance(strs,(list,tuple)):
3219 if isinstance(strs,(list,tuple)):
3219 symbols = list(strs[:])
3220 symbols = list(strs[:])
3220 elif isinstance(strs,basestring):
3221 elif isinstance(strs,basestring):
3221 symbols = strs.split()
3222 symbols = strs.split()
3222 else:
3223 else:
3223 warnings.warn("Invalid argument to oneOf, expected string or list",
3224 warnings.warn("Invalid argument to oneOf, expected string or list",
3224 SyntaxWarning, stacklevel=2)
3225 SyntaxWarning, stacklevel=2)
3225
3226
3226 i = 0
3227 i = 0
3227 while i < len(symbols)-1:
3228 while i < len(symbols)-1:
3228 cur = symbols[i]
3229 cur = symbols[i]
3229 for j,other in enumerate(symbols[i+1:]):
3230 for j,other in enumerate(symbols[i+1:]):
3230 if ( isequal(other, cur) ):
3231 if ( isequal(other, cur) ):
3231 del symbols[i+j+1]
3232 del symbols[i+j+1]
3232 break
3233 break
3233 elif ( masks(cur, other) ):
3234 elif ( masks(cur, other) ):
3234 del symbols[i+j+1]
3235 del symbols[i+j+1]
3235 symbols.insert(i,other)
3236 symbols.insert(i,other)
3236 cur = other
3237 cur = other
3237 break
3238 break
3238 else:
3239 else:
3239 i += 1
3240 i += 1
3240
3241
3241 if not caseless and useRegex:
3242 if not caseless and useRegex:
3242 #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
3243 #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
3243 try:
3244 try:
3244 if len(symbols)==len("".join(symbols)):
3245 if len(symbols)==len("".join(symbols)):
3245 return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
3246 return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
3246 else:
3247 else:
3247 return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
3248 return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
3248 except:
3249 except:
3249 warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
3250 warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
3250 SyntaxWarning, stacklevel=2)
3251 SyntaxWarning, stacklevel=2)
3251
3252
3252
3253
3253 # last resort, just use MatchFirst
3254 # last resort, just use MatchFirst
3254 return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
3255 return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
3255
3256
3256 def dictOf( key, value ):
3257 def dictOf( key, value ):
3257 """Helper to easily and clearly define a dictionary by specifying the respective patterns
3258 """Helper to easily and clearly define a dictionary by specifying the respective patterns
3258 for the key and value. Takes care of defining the Dict, ZeroOrMore, and Group tokens
3259 for the key and value. Takes care of defining the Dict, ZeroOrMore, and Group tokens
3259 in the proper order. The key pattern can include delimiting markers or punctuation,
3260 in the proper order. The key pattern can include delimiting markers or punctuation,
3260 as long as they are suppressed, thereby leaving the significant key text. The value
3261 as long as they are suppressed, thereby leaving the significant key text. The value
3261 pattern can include named results, so that the Dict results can include named token
3262 pattern can include named results, so that the Dict results can include named token
3262 fields.
3263 fields.
3263 """
3264 """
3264 return Dict( ZeroOrMore( Group ( key + value ) ) )
3265 return Dict( ZeroOrMore( Group ( key + value ) ) )
3265
3266
3266 def originalTextFor(expr, asString=True):
3267 def originalTextFor(expr, asString=True):
3267 """Helper to return the original, untokenized text for a given expression. Useful to
3268 """Helper to return the original, untokenized text for a given expression. Useful to
3268 restore the parsed fields of an HTML start tag into the raw tag text itself, or to
3269 restore the parsed fields of an HTML start tag into the raw tag text itself, or to
3269 revert separate tokens with intervening whitespace back to the original matching
3270 revert separate tokens with intervening whitespace back to the original matching
3270 input text. Simpler to use than the parse action keepOriginalText, and does not
3271 input text. Simpler to use than the parse action keepOriginalText, and does not
3271 require the inspect module to chase up the call stack. By default, returns a
3272 require the inspect module to chase up the call stack. By default, returns a
3272 string containing the original parsed text.
3273 string containing the original parsed text.
3273
3274
3274 If the optional asString argument is passed as False, then the return value is a
3275 If the optional asString argument is passed as False, then the return value is a
3275 ParseResults containing any results names that were originally matched, and a
3276 ParseResults containing any results names that were originally matched, and a
3276 single token containing the original matched text from the input string. So if
3277 single token containing the original matched text from the input string. So if
3277 the expression passed to originalTextFor contains expressions with defined
3278 the expression passed to originalTextFor contains expressions with defined
3278 results names, you must set asString to False if you want to preserve those
3279 results names, you must set asString to False if you want to preserve those
3279 results name values."""
3280 results name values."""
3280 locMarker = Empty().setParseAction(lambda s,loc,t: loc)
3281 locMarker = Empty().setParseAction(lambda s,loc,t: loc)
3281 matchExpr = locMarker("_original_start") + expr + locMarker("_original_end")
3282 matchExpr = locMarker("_original_start") + expr + locMarker("_original_end")
3282 if asString:
3283 if asString:
3283 extractText = lambda s,l,t: s[t._original_start:t._original_end]
3284 extractText = lambda s,l,t: s[t._original_start:t._original_end]
3284 else:
3285 else:
3285 def extractText(s,l,t):
3286 def extractText(s,l,t):
3286 del t[:]
3287 del t[:]
3287 t.insert(0, s[t._original_start:t._original_end])
3288 t.insert(0, s[t._original_start:t._original_end])
3288 del t["_original_start"]
3289 del t["_original_start"]
3289 del t["_original_end"]
3290 del t["_original_end"]
3290 matchExpr.setParseAction(extractText)
3291 matchExpr.setParseAction(extractText)
3291 return matchExpr
3292 return matchExpr
3292
3293
3293 # convenience constants for positional expressions
3294 # convenience constants for positional expressions
3294 empty = Empty().setName("empty")
3295 empty = Empty().setName("empty")
3295 lineStart = LineStart().setName("lineStart")
3296 lineStart = LineStart().setName("lineStart")
3296 lineEnd = LineEnd().setName("lineEnd")
3297 lineEnd = LineEnd().setName("lineEnd")
3297 stringStart = StringStart().setName("stringStart")
3298 stringStart = StringStart().setName("stringStart")
3298 stringEnd = StringEnd().setName("stringEnd")
3299 stringEnd = StringEnd().setName("stringEnd")
3299
3300
3300 _escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
3301 _escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
3301 _printables_less_backslash = "".join([ c for c in printables if c not in r"\]" ])
3302 _printables_less_backslash = "".join([ c for c in printables if c not in r"\]" ])
3302 _escapedHexChar = Combine( Suppress(_bslash + "0x") + Word(hexnums) ).setParseAction(lambda s,l,t:unichr(int(t[0],16)))
3303 _escapedHexChar = Combine( Suppress(_bslash + "0x") + Word(hexnums) ).setParseAction(lambda s,l,t:unichr(int(t[0],16)))
3303 _escapedOctChar = Combine( Suppress(_bslash) + Word("0","01234567") ).setParseAction(lambda s,l,t:unichr(int(t[0],8)))
3304 _escapedOctChar = Combine( Suppress(_bslash) + Word("0","01234567") ).setParseAction(lambda s,l,t:unichr(int(t[0],8)))
3304 _singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
3305 _singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
3305 _charRange = Group(_singleChar + Suppress("-") + _singleChar)
3306 _charRange = Group(_singleChar + Suppress("-") + _singleChar)
3306 _reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
3307 _reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
3307
3308
3308 _expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
3309 _expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
3309
3310
3310 def srange(s):
3311 def srange(s):
3311 r"""Helper to easily define string ranges for use in Word construction. Borrows
3312 r"""Helper to easily define string ranges for use in Word construction. Borrows
3312 syntax from regexp '[]' string range definitions::
3313 syntax from regexp '[]' string range definitions::
3313 srange("[0-9]") -> "0123456789"
3314 srange("[0-9]") -> "0123456789"
3314 srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz"
3315 srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz"
3315 srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
3316 srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
3316 The input string must be enclosed in []'s, and the returned string is the expanded
3317 The input string must be enclosed in []'s, and the returned string is the expanded
3317 character set joined into a single string.
3318 character set joined into a single string.
3318 The values enclosed in the []'s may be::
3319 The values enclosed in the []'s may be::
3319 a single character
3320 a single character
3320 an escaped character with a leading backslash (such as \- or \])
3321 an escaped character with a leading backslash (such as \- or \])
3321 an escaped hex character with a leading '\0x' (\0x21, which is a '!' character)
3322 an escaped hex character with a leading '\0x' (\0x21, which is a '!' character)
3322 an escaped octal character with a leading '\0' (\041, which is a '!' character)
3323 an escaped octal character with a leading '\0' (\041, which is a '!' character)
3323 a range of any of the above, separated by a dash ('a-z', etc.)
3324 a range of any of the above, separated by a dash ('a-z', etc.)
3324 any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
3325 any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
3325 """
3326 """
3326 try:
3327 try:
3327 return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
3328 return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
3328 except:
3329 except:
3329 return ""
3330 return ""
3330
3331
3331 def matchOnlyAtCol(n):
3332 def matchOnlyAtCol(n):
3332 """Helper method for defining parse actions that require matching at a specific
3333 """Helper method for defining parse actions that require matching at a specific
3333 column in the input text.
3334 column in the input text.
3334 """
3335 """
3335 def verifyCol(strg,locn,toks):
3336 def verifyCol(strg,locn,toks):
3336 if col(locn,strg) != n:
3337 if col(locn,strg) != n:
3337 raise ParseException(strg,locn,"matched token not at column %d" % n)
3338 raise ParseException(strg,locn,"matched token not at column %d" % n)
3338 return verifyCol
3339 return verifyCol
3339
3340
3340 def replaceWith(replStr):
3341 def replaceWith(replStr):
3341 """Helper method for common parse actions that simply return a literal value. Especially
3342 """Helper method for common parse actions that simply return a literal value. Especially
3342 useful when used with transformString().
3343 useful when used with transformString().
3343 """
3344 """
3344 def _replFunc(*args):
3345 def _replFunc(*args):
3345 return [replStr]
3346 return [replStr]
3346 return _replFunc
3347 return _replFunc
3347
3348
3348 def removeQuotes(s,l,t):
3349 def removeQuotes(s,l,t):
3349 """Helper parse action for removing quotation marks from parsed quoted strings.
3350 """Helper parse action for removing quotation marks from parsed quoted strings.
3350 To use, add this parse action to quoted string using::
3351 To use, add this parse action to quoted string using::
3351 quotedString.setParseAction( removeQuotes )
3352 quotedString.setParseAction( removeQuotes )
3352 """
3353 """
3353 return t[0][1:-1]
3354 return t[0][1:-1]
3354
3355
3355 def upcaseTokens(s,l,t):
3356 def upcaseTokens(s,l,t):
3356 """Helper parse action to convert tokens to upper case."""
3357 """Helper parse action to convert tokens to upper case."""
3357 return [ tt.upper() for tt in map(_ustr,t) ]
3358 return [ tt.upper() for tt in map(_ustr,t) ]
3358
3359
3359 def downcaseTokens(s,l,t):
3360 def downcaseTokens(s,l,t):
3360 """Helper parse action to convert tokens to lower case."""
3361 """Helper parse action to convert tokens to lower case."""
3361 return [ tt.lower() for tt in map(_ustr,t) ]
3362 return [ tt.lower() for tt in map(_ustr,t) ]
3362
3363
3363 def keepOriginalText(s,startLoc,t):
3364 def keepOriginalText(s,startLoc,t):
3364 """Helper parse action to preserve original parsed text,
3365 """Helper parse action to preserve original parsed text,
3365 overriding any nested parse actions."""
3366 overriding any nested parse actions."""
3366 try:
3367 try:
3367 endloc = getTokensEndLoc()
3368 endloc = getTokensEndLoc()
3368 except ParseException:
3369 except ParseException:
3369 raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action")
3370 raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action")
3370 del t[:]
3371 del t[:]
3371 t += ParseResults(s[startLoc:endloc])
3372 t += ParseResults(s[startLoc:endloc])
3372 return t
3373 return t
3373
3374
3374 def getTokensEndLoc():
3375 def getTokensEndLoc():
3375 """Method to be called from within a parse action to determine the end
3376 """Method to be called from within a parse action to determine the end
3376 location of the parsed tokens."""
3377 location of the parsed tokens."""
3377 import inspect
3378 import inspect
3378 fstack = inspect.stack()
3379 fstack = inspect.stack()
3379 try:
3380 try:
3380 # search up the stack (through intervening argument normalizers) for correct calling routine
3381 # search up the stack (through intervening argument normalizers) for correct calling routine
3381 for f in fstack[2:]:
3382 for f in fstack[2:]:
3382 if f[3] == "_parseNoCache":
3383 if f[3] == "_parseNoCache":
3383 endloc = f[0].f_locals["loc"]
3384 endloc = f[0].f_locals["loc"]
3384 return endloc
3385 return endloc
3385 else:
3386 else:
3386 raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action")
3387 raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action")
3387 finally:
3388 finally:
3388 del fstack
3389 del fstack
3389
3390
3390 def _makeTags(tagStr, xml):
3391 def _makeTags(tagStr, xml):
3391 """Internal helper to construct opening and closing tag expressions, given a tag name"""
3392 """Internal helper to construct opening and closing tag expressions, given a tag name"""
3392 if isinstance(tagStr,basestring):
3393 if isinstance(tagStr,basestring):
3393 resname = tagStr
3394 resname = tagStr
3394 tagStr = Keyword(tagStr, caseless=not xml)
3395 tagStr = Keyword(tagStr, caseless=not xml)
3395 else:
3396 else:
3396 resname = tagStr.name
3397 resname = tagStr.name
3397
3398
3398 tagAttrName = Word(alphas,alphanums+"_-:")
3399 tagAttrName = Word(alphas,alphanums+"_-:")
3399 if (xml):
3400 if (xml):
3400 tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
3401 tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
3401 openTag = Suppress("<") + tagStr + \
3402 openTag = Suppress("<") + tagStr + \
3402 Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
3403 Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
3403 Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
3404 Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
3404 else:
3405 else:
3405 printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
3406 printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
3406 tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
3407 tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
3407 openTag = Suppress("<") + tagStr + \
3408 openTag = Suppress("<") + tagStr + \
3408 Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
3409 Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
3409 Optional( Suppress("=") + tagAttrValue ) ))) + \
3410 Optional( Suppress("=") + tagAttrValue ) ))) + \
3410 Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
3411 Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
3411 closeTag = Combine(_L("</") + tagStr + ">")
3412 closeTag = Combine(_L("</") + tagStr + ">")
3412
3413
3413 openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
3414 openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
3414 closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % tagStr)
3415 closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % tagStr)
3415
3416
3416 return openTag, closeTag
3417 return openTag, closeTag
3417
3418
3418 def makeHTMLTags(tagStr):
3419 def makeHTMLTags(tagStr):
3419 """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
3420 """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
3420 return _makeTags( tagStr, False )
3421 return _makeTags( tagStr, False )
3421
3422
3422 def makeXMLTags(tagStr):
3423 def makeXMLTags(tagStr):
3423 """Helper to construct opening and closing tag expressions for XML, given a tag name"""
3424 """Helper to construct opening and closing tag expressions for XML, given a tag name"""
3424 return _makeTags( tagStr, True )
3425 return _makeTags( tagStr, True )
3425
3426
3426 def withAttribute(*args,**attrDict):
3427 def withAttribute(*args,**attrDict):
3427 """Helper to create a validating parse action to be used with start tags created
3428 """Helper to create a validating parse action to be used with start tags created
3428 with makeXMLTags or makeHTMLTags. Use withAttribute to qualify a starting tag
3429 with makeXMLTags or makeHTMLTags. Use withAttribute to qualify a starting tag
3429 with a required attribute value, to avoid false matches on common tags such as
3430 with a required attribute value, to avoid false matches on common tags such as
3430 <TD> or <DIV>.
3431 <TD> or <DIV>.
3431
3432
3432 Call withAttribute with a series of attribute names and values. Specify the list
3433 Call withAttribute with a series of attribute names and values. Specify the list
3433 of filter attributes names and values as:
3434 of filter attributes names and values as:
3434 - keyword arguments, as in (class="Customer",align="right"), or
3435 - keyword arguments, as in (class="Customer",align="right"), or
3435 - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
3436 - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
3436 For attribute names with a namespace prefix, you must use the second form. Attribute
3437 For attribute names with a namespace prefix, you must use the second form. Attribute
3437 names are matched insensitive to upper/lower case.
3438 names are matched insensitive to upper/lower case.
3438
3439
3439 To verify that the attribute exists, but without specifying a value, pass
3440 To verify that the attribute exists, but without specifying a value, pass
3440 withAttribute.ANY_VALUE as the value.
3441 withAttribute.ANY_VALUE as the value.
3441 """
3442 """
3442 if args:
3443 if args:
3443 attrs = args[:]
3444 attrs = args[:]
3444 else:
3445 else:
3445 attrs = attrDict.items()
3446 attrs = attrDict.iteritems()
3446 attrs = [(k,v) for k,v in attrs]
3447 attrs = [(k,v) for k,v in attrs]
3447 def pa(s,l,tokens):
3448 def pa(s,l,tokens):
3448 for attrName,attrValue in attrs:
3449 for attrName,attrValue in attrs:
3449 if attrName not in tokens:
3450 if attrName not in tokens:
3450 raise ParseException(s,l,"no matching attribute " + attrName)
3451 raise ParseException(s,l,"no matching attribute " + attrName)
3451 if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
3452 if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
3452 raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
3453 raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
3453 (attrName, tokens[attrName], attrValue))
3454 (attrName, tokens[attrName], attrValue))
3454 return pa
3455 return pa
3455 withAttribute.ANY_VALUE = object()
3456 withAttribute.ANY_VALUE = object()
3456
3457
3457 opAssoc = _Constants()
3458 opAssoc = _Constants()
3458 opAssoc.LEFT = object()
3459 opAssoc.LEFT = object()
3459 opAssoc.RIGHT = object()
3460 opAssoc.RIGHT = object()
3460
3461
3461 def operatorPrecedence( baseExpr, opList ):
3462 def operatorPrecedence( baseExpr, opList ):
3462 """Helper method for constructing grammars of expressions made up of
3463 """Helper method for constructing grammars of expressions made up of
3463 operators working in a precedence hierarchy. Operators may be unary or
3464 operators working in a precedence hierarchy. Operators may be unary or
3464 binary, left- or right-associative. Parse actions can also be attached
3465 binary, left- or right-associative. Parse actions can also be attached
3465 to operator expressions.
3466 to operator expressions.
3466
3467
3467 Parameters:
3468 Parameters:
3468 - baseExpr - expression representing the most basic element for the nested
3469 - baseExpr - expression representing the most basic element for the nested
3469 - opList - list of tuples, one for each operator precedence level in the
3470 - opList - list of tuples, one for each operator precedence level in the
3470 expression grammar; each tuple is of the form
3471 expression grammar; each tuple is of the form
3471 (opExpr, numTerms, rightLeftAssoc, parseAction), where:
3472 (opExpr, numTerms, rightLeftAssoc, parseAction), where:
3472 - opExpr is the pyparsing expression for the operator;
3473 - opExpr is the pyparsing expression for the operator;
3473 may also be a string, which will be converted to a Literal;
3474 may also be a string, which will be converted to a Literal;
3474 if numTerms is 3, opExpr is a tuple of two expressions, for the
3475 if numTerms is 3, opExpr is a tuple of two expressions, for the
3475 two operators separating the 3 terms
3476 two operators separating the 3 terms
3476 - numTerms is the number of terms for this operator (must
3477 - numTerms is the number of terms for this operator (must
3477 be 1, 2, or 3)
3478 be 1, 2, or 3)
3478 - rightLeftAssoc is the indicator whether the operator is
3479 - rightLeftAssoc is the indicator whether the operator is
3479 right or left associative, using the pyparsing-defined
3480 right or left associative, using the pyparsing-defined
3480 constants opAssoc.RIGHT and opAssoc.LEFT.
3481 constants opAssoc.RIGHT and opAssoc.LEFT.
3481 - parseAction is the parse action to be associated with
3482 - parseAction is the parse action to be associated with
3482 expressions matching this operator expression (the
3483 expressions matching this operator expression (the
3483 parse action tuple member may be omitted)
3484 parse action tuple member may be omitted)
3484 """
3485 """
3485 ret = Forward()
3486 ret = Forward()
3486 lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
3487 lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
3487 for i,operDef in enumerate(opList):
3488 for i,operDef in enumerate(opList):
3488 opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
3489 opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
3489 if arity == 3:
3490 if arity == 3:
3490 if opExpr is None or len(opExpr) != 2:
3491 if opExpr is None or len(opExpr) != 2:
3491 raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
3492 raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
3492 opExpr1, opExpr2 = opExpr
3493 opExpr1, opExpr2 = opExpr
3493 thisExpr = Forward()#.setName("expr%d" % i)
3494 thisExpr = Forward()#.setName("expr%d" % i)
3494 if rightLeftAssoc == opAssoc.LEFT:
3495 if rightLeftAssoc == opAssoc.LEFT:
3495 if arity == 1:
3496 if arity == 1:
3496 matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
3497 matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
3497 elif arity == 2:
3498 elif arity == 2:
3498 if opExpr is not None:
3499 if opExpr is not None:
3499 matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
3500 matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
3500 else:
3501 else:
3501 matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
3502 matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
3502 elif arity == 3:
3503 elif arity == 3:
3503 matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
3504 matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
3504 Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
3505 Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
3505 else:
3506 else:
3506 raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
3507 raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
3507 elif rightLeftAssoc == opAssoc.RIGHT:
3508 elif rightLeftAssoc == opAssoc.RIGHT:
3508 if arity == 1:
3509 if arity == 1:
3509 # try to avoid LR with this extra test
3510 # try to avoid LR with this extra test
3510 if not isinstance(opExpr, Optional):
3511 if not isinstance(opExpr, Optional):
3511 opExpr = Optional(opExpr)
3512 opExpr = Optional(opExpr)
3512 matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
3513 matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
3513 elif arity == 2:
3514 elif arity == 2:
3514 if opExpr is not None:
3515 if opExpr is not None:
3515 matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
3516 matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
3516 else:
3517 else:
3517 matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
3518 matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
3518 elif arity == 3:
3519 elif arity == 3:
3519 matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
3520 matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
3520 Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
3521 Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
3521 else:
3522 else:
3522 raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
3523 raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
3523 else:
3524 else:
3524 raise ValueError("operator must indicate right or left associativity")
3525 raise ValueError("operator must indicate right or left associativity")
3525 if pa:
3526 if pa:
3526 matchExpr.setParseAction( pa )
3527 matchExpr.setParseAction( pa )
3527 thisExpr << ( matchExpr | lastExpr )
3528 thisExpr << ( matchExpr | lastExpr )
3528 lastExpr = thisExpr
3529 lastExpr = thisExpr
3529 ret << lastExpr
3530 ret << lastExpr
3530 return ret
3531 return ret
3531
3532
3532 dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes")
3533 dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes")
3533 sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes")
3534 sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes")
3534 quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes")
3535 quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes")
3535 unicodeString = Combine(_L('u') + quotedString.copy())
3536 unicodeString = Combine(_L('u') + quotedString.copy())
3536
3537
3537 def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString):
3538 def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString):
3538 """Helper method for defining nested lists enclosed in opening and closing
3539 """Helper method for defining nested lists enclosed in opening and closing
3539 delimiters ("(" and ")" are the default).
3540 delimiters ("(" and ")" are the default).
3540
3541
3541 Parameters:
3542 Parameters:
3542 - opener - opening character for a nested list (default="("); can also be a pyparsing expression
3543 - opener - opening character for a nested list (default="("); can also be a pyparsing expression
3543 - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
3544 - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
3544 - content - expression for items within the nested lists (default=None)
3545 - content - expression for items within the nested lists (default=None)
3545 - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
3546 - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
3546
3547
3547 If an expression is not provided for the content argument, the nested
3548 If an expression is not provided for the content argument, the nested
3548 expression will capture all whitespace-delimited content between delimiters
3549 expression will capture all whitespace-delimited content between delimiters
3549 as a list of separate values.
3550 as a list of separate values.
3550
3551
3551 Use the ignoreExpr argument to define expressions that may contain
3552 Use the ignoreExpr argument to define expressions that may contain
3552 opening or closing characters that should not be treated as opening
3553 opening or closing characters that should not be treated as opening
3553 or closing characters for nesting, such as quotedString or a comment
3554 or closing characters for nesting, such as quotedString or a comment
3554 expression. Specify multiple expressions using an Or or MatchFirst.
3555 expression. Specify multiple expressions using an Or or MatchFirst.
3555 The default is quotedString, but if no expressions are to be ignored,
3556 The default is quotedString, but if no expressions are to be ignored,
3556 then pass None for this argument.
3557 then pass None for this argument.
3557 """
3558 """
3558 if opener == closer:
3559 if opener == closer:
3559 raise ValueError("opening and closing strings cannot be the same")
3560 raise ValueError("opening and closing strings cannot be the same")
3560 if content is None:
3561 if content is None:
3561 if isinstance(opener,basestring) and isinstance(closer,basestring):
3562 if isinstance(opener,basestring) and isinstance(closer,basestring):
3562 if len(opener) == 1 and len(closer)==1:
3563 if len(opener) == 1 and len(closer)==1:
3563 if ignoreExpr is not None:
3564 if ignoreExpr is not None:
3564 content = (Combine(OneOrMore(~ignoreExpr +
3565 content = (Combine(OneOrMore(~ignoreExpr +
3565 CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3566 CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3566 ).setParseAction(lambda t:t[0].strip()))
3567 ).setParseAction(lambda t:t[0].strip()))
3567 else:
3568 else:
3568 content = (empty+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
3569 content = (empty+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
3569 ).setParseAction(lambda t:t[0].strip()))
3570 ).setParseAction(lambda t:t[0].strip()))
3570 else:
3571 else:
3571 if ignoreExpr is not None:
3572 if ignoreExpr is not None:
3572 content = (Combine(OneOrMore(~ignoreExpr +
3573 content = (Combine(OneOrMore(~ignoreExpr +
3573 ~Literal(opener) + ~Literal(closer) +
3574 ~Literal(opener) + ~Literal(closer) +
3574 CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3575 CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3575 ).setParseAction(lambda t:t[0].strip()))
3576 ).setParseAction(lambda t:t[0].strip()))
3576 else:
3577 else:
3577 content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
3578 content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
3578 CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3579 CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3579 ).setParseAction(lambda t:t[0].strip()))
3580 ).setParseAction(lambda t:t[0].strip()))
3580 else:
3581 else:
3581 raise ValueError("opening and closing arguments must be strings if no content expression is given")
3582 raise ValueError("opening and closing arguments must be strings if no content expression is given")
3582 ret = Forward()
3583 ret = Forward()
3583 if ignoreExpr is not None:
3584 if ignoreExpr is not None:
3584 ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
3585 ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
3585 else:
3586 else:
3586 ret << Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) )
3587 ret << Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) )
3587 return ret
3588 return ret
3588
3589
3589 def indentedBlock(blockStatementExpr, indentStack, indent=True):
3590 def indentedBlock(blockStatementExpr, indentStack, indent=True):
3590 """Helper method for defining space-delimited indentation blocks, such as
3591 """Helper method for defining space-delimited indentation blocks, such as
3591 those used to define block statements in Python source code.
3592 those used to define block statements in Python source code.
3592
3593
3593 Parameters:
3594 Parameters:
3594 - blockStatementExpr - expression defining syntax of statement that
3595 - blockStatementExpr - expression defining syntax of statement that
3595 is repeated within the indented block
3596 is repeated within the indented block
3596 - indentStack - list created by caller to manage indentation stack
3597 - indentStack - list created by caller to manage indentation stack
3597 (multiple statementWithIndentedBlock expressions within a single grammar
3598 (multiple statementWithIndentedBlock expressions within a single grammar
3598 should share a common indentStack)
3599 should share a common indentStack)
3599 - indent - boolean indicating whether block must be indented beyond the
3600 - indent - boolean indicating whether block must be indented beyond the
3600 the current level; set to False for block of left-most statements
3601 the current level; set to False for block of left-most statements
3601 (default=True)
3602 (default=True)
3602
3603
3603 A valid block must contain at least one blockStatement.
3604 A valid block must contain at least one blockStatement.
3604 """
3605 """
3605 def checkPeerIndent(s,l,t):
3606 def checkPeerIndent(s,l,t):
3606 if l >= len(s): return
3607 if l >= len(s): return
3607 curCol = col(l,s)
3608 curCol = col(l,s)
3608 if curCol != indentStack[-1]:
3609 if curCol != indentStack[-1]:
3609 if curCol > indentStack[-1]:
3610 if curCol > indentStack[-1]:
3610 raise ParseFatalException(s,l,"illegal nesting")
3611 raise ParseFatalException(s,l,"illegal nesting")
3611 raise ParseException(s,l,"not a peer entry")
3612 raise ParseException(s,l,"not a peer entry")
3612
3613
3613 def checkSubIndent(s,l,t):
3614 def checkSubIndent(s,l,t):
3614 curCol = col(l,s)
3615 curCol = col(l,s)
3615 if curCol > indentStack[-1]:
3616 if curCol > indentStack[-1]:
3616 indentStack.append( curCol )
3617 indentStack.append( curCol )
3617 else:
3618 else:
3618 raise ParseException(s,l,"not a subentry")
3619 raise ParseException(s,l,"not a subentry")
3619
3620
3620 def checkUnindent(s,l,t):
3621 def checkUnindent(s,l,t):
3621 if l >= len(s): return
3622 if l >= len(s): return
3622 curCol = col(l,s)
3623 curCol = col(l,s)
3623 if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
3624 if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
3624 raise ParseException(s,l,"not an unindent")
3625 raise ParseException(s,l,"not an unindent")
3625 indentStack.pop()
3626 indentStack.pop()
3626
3627
3627 NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
3628 NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
3628 INDENT = Empty() + Empty().setParseAction(checkSubIndent)
3629 INDENT = Empty() + Empty().setParseAction(checkSubIndent)
3629 PEER = Empty().setParseAction(checkPeerIndent)
3630 PEER = Empty().setParseAction(checkPeerIndent)
3630 UNDENT = Empty().setParseAction(checkUnindent)
3631 UNDENT = Empty().setParseAction(checkUnindent)
3631 if indent:
3632 if indent:
3632 smExpr = Group( Optional(NL) +
3633 smExpr = Group( Optional(NL) +
3633 FollowedBy(blockStatementExpr) +
3634 FollowedBy(blockStatementExpr) +
3634 INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
3635 INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
3635 else:
3636 else:
3636 smExpr = Group( Optional(NL) +
3637 smExpr = Group( Optional(NL) +
3637 (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
3638 (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
3638 blockStatementExpr.ignore(_bslash + LineEnd())
3639 blockStatementExpr.ignore(_bslash + LineEnd())
3639 return smExpr
3640 return smExpr
3640
3641
3641 alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
3642 alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
3642 punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
3643 punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
3643
3644
3644 anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:"))
3645 anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:"))
3645 commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline()
3646 commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline()
3646 _htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "'))
3647 _htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "'))
3647 replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
3648 replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
3648
3649
3649 # it's easy to get these comment structures wrong - they're very common, so may as well make them available
3650 # it's easy to get these comment structures wrong - they're very common, so may as well make them available
3650 cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
3651 cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
3651
3652
3652 htmlComment = Regex(r"<!--[\s\S]*?-->")
3653 htmlComment = Regex(r"<!--[\s\S]*?-->")
3653 restOfLine = Regex(r".*").leaveWhitespace()
3654 restOfLine = Regex(r".*").leaveWhitespace()
3654 dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
3655 dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
3655 cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))").setName("C++ style comment")
3656 cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))").setName("C++ style comment")
3656
3657
3657 javaStyleComment = cppStyleComment
3658 javaStyleComment = cppStyleComment
3658 pythonStyleComment = Regex(r"#.*").setName("Python style comment")
3659 pythonStyleComment = Regex(r"#.*").setName("Python style comment")
3659 _noncomma = "".join( [ c for c in printables if c != "," ] )
3660 _noncomma = "".join( [ c for c in printables if c != "," ] )
3660 _commasepitem = Combine(OneOrMore(Word(_noncomma) +
3661 _commasepitem = Combine(OneOrMore(Word(_noncomma) +
3661 Optional( Word(" \t") +
3662 Optional( Word(" \t") +
3662 ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
3663 ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
3663 commaSeparatedList = delimitedList( Optional( quotedString | _commasepitem, default="") ).setName("commaSeparatedList")
3664 commaSeparatedList = delimitedList( Optional( quotedString | _commasepitem, default="") ).setName("commaSeparatedList")
3664
3665
3665
3666
3666 if __name__ == "__main__":
3667 if __name__ == "__main__":
3667
3668
3668 def test( teststring ):
3669 def test( teststring ):
3669 try:
3670 try:
3670 tokens = simpleSQL.parseString( teststring )
3671 tokens = simpleSQL.parseString( teststring )
3671 tokenlist = tokens.asList()
3672 tokenlist = tokens.asList()
3672 print (teststring + "->" + str(tokenlist))
3673 print (teststring + "->" + str(tokenlist))
3673 print ("tokens = " + str(tokens))
3674 print ("tokens = " + str(tokens))
3674 print ("tokens.columns = " + str(tokens.columns))
3675 print ("tokens.columns = " + str(tokens.columns))
3675 print ("tokens.tables = " + str(tokens.tables))
3676 print ("tokens.tables = " + str(tokens.tables))
3676 print (tokens.asXML("SQL",True))
3677 print (tokens.asXML("SQL",True))
3677 except ParseBaseException,err:
3678 except ParseBaseException,err:
3678 print (teststring + "->")
3679 print (teststring + "->")
3679 print (err.line)
3680 print (err.line)
3680 print (" "*(err.column-1) + "^")
3681 print (" "*(err.column-1) + "^")
3681 print (err)
3682 print (err)
3682 print()
3683 print()
3683
3684
3684 selectToken = CaselessLiteral( "select" )
3685 selectToken = CaselessLiteral( "select" )
3685 fromToken = CaselessLiteral( "from" )
3686 fromToken = CaselessLiteral( "from" )
3686
3687
3687 ident = Word( alphas, alphanums + "_$" )
3688 ident = Word( alphas, alphanums + "_$" )
3688 columnName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
3689 columnName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
3689 columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
3690 columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
3690 tableName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
3691 tableName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
3691 tableNameList = Group( delimitedList( tableName ) )#.setName("tables")
3692 tableNameList = Group( delimitedList( tableName ) )#.setName("tables")
3692 simpleSQL = ( selectToken + \
3693 simpleSQL = ( selectToken + \
3693 ( '*' | columnNameList ).setResultsName( "columns" ) + \
3694 ( '*' | columnNameList ).setResultsName( "columns" ) + \
3694 fromToken + \
3695 fromToken + \
3695 tableNameList.setResultsName( "tables" ) )
3696 tableNameList.setResultsName( "tables" ) )
3696
3697
3697 test( "SELECT * from XYZZY, ABC" )
3698 test( "SELECT * from XYZZY, ABC" )
3698 test( "select * from SYS.XYZZY" )
3699 test( "select * from SYS.XYZZY" )
3699 test( "Select A from Sys.dual" )
3700 test( "Select A from Sys.dual" )
3700 test( "Select AA,BB,CC from Sys.dual" )
3701 test( "Select AA,BB,CC from Sys.dual" )
3701 test( "Select A, B, C from Sys.dual" )
3702 test( "Select A, B, C from Sys.dual" )
3702 test( "Select A, B, C from Sys.dual" )
3703 test( "Select A, B, C from Sys.dual" )
3703 test( "Xelect A, B, C from Sys.dual" )
3704 test( "Xelect A, B, C from Sys.dual" )
3704 test( "Select A, B, C frox Sys.dual" )
3705 test( "Select A, B, C frox Sys.dual" )
3705 test( "Select" )
3706 test( "Select" )
3706 test( "Select ^^^ frox Sys.dual" )
3707 test( "Select ^^^ frox Sys.dual" )
3707 test( "Select A, B, C from Sys.dual, Table2 " )
3708 test( "Select A, B, C from Sys.dual, Table2 " )
@@ -1,834 +1,834 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Facilities for launching IPython processes asynchronously.
4 Facilities for launching IPython processes asynchronously.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21
21
22 from IPython.config.configurable import Configurable
22 from IPython.config.configurable import Configurable
23 from IPython.external import Itpl
23 from IPython.external import Itpl
24 from IPython.utils.traitlets import Str, Int, List, Unicode
24 from IPython.utils.traitlets import Str, Int, List, Unicode
25 from IPython.utils.path import get_ipython_module_path
25 from IPython.utils.path import get_ipython_module_path
26 from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError
26 from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError
27 from IPython.kernel.twistedutil import (
27 from IPython.kernel.twistedutil import (
28 gatherBoth,
28 gatherBoth,
29 make_deferred,
29 make_deferred,
30 sleep_deferred
30 sleep_deferred
31 )
31 )
32 from IPython.kernel.winhpcjob import (
32 from IPython.kernel.winhpcjob import (
33 IPControllerTask, IPEngineTask,
33 IPControllerTask, IPEngineTask,
34 IPControllerJob, IPEngineSetJob
34 IPControllerJob, IPEngineSetJob
35 )
35 )
36
36
37 from twisted.internet import reactor, defer
37 from twisted.internet import reactor, defer
38 from twisted.internet.defer import inlineCallbacks
38 from twisted.internet.defer import inlineCallbacks
39 from twisted.internet.protocol import ProcessProtocol
39 from twisted.internet.protocol import ProcessProtocol
40 from twisted.internet.utils import getProcessOutput
40 from twisted.internet.utils import getProcessOutput
41 from twisted.internet.error import ProcessDone, ProcessTerminated
41 from twisted.internet.error import ProcessDone, ProcessTerminated
42 from twisted.python import log
42 from twisted.python import log
43 from twisted.python.failure import Failure
43 from twisted.python.failure import Failure
44
44
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Paths to the kernel apps
47 # Paths to the kernel apps
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 ipcluster_cmd_argv = pycmd2argv(get_ipython_module_path(
51 ipcluster_cmd_argv = pycmd2argv(get_ipython_module_path(
52 'IPython.kernel.ipclusterapp'
52 'IPython.kernel.ipclusterapp'
53 ))
53 ))
54
54
55 ipengine_cmd_argv = pycmd2argv(get_ipython_module_path(
55 ipengine_cmd_argv = pycmd2argv(get_ipython_module_path(
56 'IPython.kernel.ipengineapp'
56 'IPython.kernel.ipengineapp'
57 ))
57 ))
58
58
59 ipcontroller_cmd_argv = pycmd2argv(get_ipython_module_path(
59 ipcontroller_cmd_argv = pycmd2argv(get_ipython_module_path(
60 'IPython.kernel.ipcontrollerapp'
60 'IPython.kernel.ipcontrollerapp'
61 ))
61 ))
62
62
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 # Base launchers and errors
64 # Base launchers and errors
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67
67
68 class LauncherError(Exception):
68 class LauncherError(Exception):
69 pass
69 pass
70
70
71
71
72 class ProcessStateError(LauncherError):
72 class ProcessStateError(LauncherError):
73 pass
73 pass
74
74
75
75
76 class UnknownStatus(LauncherError):
76 class UnknownStatus(LauncherError):
77 pass
77 pass
78
78
79
79
80 class BaseLauncher(Configurable):
80 class BaseLauncher(Configurable):
81 """An asbtraction for starting, stopping and signaling a process."""
81 """An asbtraction for starting, stopping and signaling a process."""
82
82
83 # In all of the launchers, the work_dir is where child processes will be
83 # In all of the launchers, the work_dir is where child processes will be
84 # run. This will usually be the cluster_dir, but may not be. any work_dir
84 # run. This will usually be the cluster_dir, but may not be. any work_dir
85 # passed into the __init__ method will override the config value.
85 # passed into the __init__ method will override the config value.
86 # This should not be used to set the work_dir for the actual engine
86 # This should not be used to set the work_dir for the actual engine
87 # and controller. Instead, use their own config files or the
87 # and controller. Instead, use their own config files or the
88 # controller_args, engine_args attributes of the launchers to add
88 # controller_args, engine_args attributes of the launchers to add
89 # the --work-dir option.
89 # the --work-dir option.
90 work_dir = Unicode(u'')
90 work_dir = Unicode(u'')
91
91
92 def __init__(self, work_dir=u'', config=None):
92 def __init__(self, work_dir=u'', config=None):
93 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config)
93 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config)
94 self.state = 'before' # can be before, running, after
94 self.state = 'before' # can be before, running, after
95 self.stop_deferreds = []
95 self.stop_deferreds = []
96 self.start_data = None
96 self.start_data = None
97 self.stop_data = None
97 self.stop_data = None
98
98
99 @property
99 @property
100 def args(self):
100 def args(self):
101 """A list of cmd and args that will be used to start the process.
101 """A list of cmd and args that will be used to start the process.
102
102
103 This is what is passed to :func:`spawnProcess` and the first element
103 This is what is passed to :func:`spawnProcess` and the first element
104 will be the process name.
104 will be the process name.
105 """
105 """
106 return self.find_args()
106 return self.find_args()
107
107
108 def find_args(self):
108 def find_args(self):
109 """The ``.args`` property calls this to find the args list.
109 """The ``.args`` property calls this to find the args list.
110
110
111 Subcommand should implement this to construct the cmd and args.
111 Subcommand should implement this to construct the cmd and args.
112 """
112 """
113 raise NotImplementedError('find_args must be implemented in a subclass')
113 raise NotImplementedError('find_args must be implemented in a subclass')
114
114
115 @property
115 @property
116 def arg_str(self):
116 def arg_str(self):
117 """The string form of the program arguments."""
117 """The string form of the program arguments."""
118 return ' '.join(self.args)
118 return ' '.join(self.args)
119
119
120 @property
120 @property
121 def running(self):
121 def running(self):
122 """Am I running."""
122 """Am I running."""
123 if self.state == 'running':
123 if self.state == 'running':
124 return True
124 return True
125 else:
125 else:
126 return False
126 return False
127
127
128 def start(self):
128 def start(self):
129 """Start the process.
129 """Start the process.
130
130
131 This must return a deferred that fires with information about the
131 This must return a deferred that fires with information about the
132 process starting (like a pid, job id, etc.).
132 process starting (like a pid, job id, etc.).
133 """
133 """
134 return defer.fail(
134 return defer.fail(
135 Failure(NotImplementedError(
135 Failure(NotImplementedError(
136 'start must be implemented in a subclass')
136 'start must be implemented in a subclass')
137 )
137 )
138 )
138 )
139
139
140 def stop(self):
140 def stop(self):
141 """Stop the process and notify observers of stopping.
141 """Stop the process and notify observers of stopping.
142
142
143 This must return a deferred that fires with information about the
143 This must return a deferred that fires with information about the
144 processing stopping, like errors that occur while the process is
144 processing stopping, like errors that occur while the process is
145 attempting to be shut down. This deferred won't fire when the process
145 attempting to be shut down. This deferred won't fire when the process
146 actually stops. To observe the actual process stopping, see
146 actually stops. To observe the actual process stopping, see
147 :func:`observe_stop`.
147 :func:`observe_stop`.
148 """
148 """
149 return defer.fail(
149 return defer.fail(
150 Failure(NotImplementedError(
150 Failure(NotImplementedError(
151 'stop must be implemented in a subclass')
151 'stop must be implemented in a subclass')
152 )
152 )
153 )
153 )
154
154
155 def observe_stop(self):
155 def observe_stop(self):
156 """Get a deferred that will fire when the process stops.
156 """Get a deferred that will fire when the process stops.
157
157
158 The deferred will fire with data that contains information about
158 The deferred will fire with data that contains information about
159 the exit status of the process.
159 the exit status of the process.
160 """
160 """
161 if self.state=='after':
161 if self.state=='after':
162 return defer.succeed(self.stop_data)
162 return defer.succeed(self.stop_data)
163 else:
163 else:
164 d = defer.Deferred()
164 d = defer.Deferred()
165 self.stop_deferreds.append(d)
165 self.stop_deferreds.append(d)
166 return d
166 return d
167
167
168 def notify_start(self, data):
168 def notify_start(self, data):
169 """Call this to trigger startup actions.
169 """Call this to trigger startup actions.
170
170
171 This logs the process startup and sets the state to 'running'. It is
171 This logs the process startup and sets the state to 'running'. It is
172 a pass-through so it can be used as a callback.
172 a pass-through so it can be used as a callback.
173 """
173 """
174
174
175 log.msg('Process %r started: %r' % (self.args[0], data))
175 log.msg('Process %r started: %r' % (self.args[0], data))
176 self.start_data = data
176 self.start_data = data
177 self.state = 'running'
177 self.state = 'running'
178 return data
178 return data
179
179
180 def notify_stop(self, data):
180 def notify_stop(self, data):
181 """Call this to trigger process stop actions.
181 """Call this to trigger process stop actions.
182
182
183 This logs the process stopping and sets the state to 'after'. Call
183 This logs the process stopping and sets the state to 'after'. Call
184 this to trigger all the deferreds from :func:`observe_stop`."""
184 this to trigger all the deferreds from :func:`observe_stop`."""
185
185
186 log.msg('Process %r stopped: %r' % (self.args[0], data))
186 log.msg('Process %r stopped: %r' % (self.args[0], data))
187 self.stop_data = data
187 self.stop_data = data
188 self.state = 'after'
188 self.state = 'after'
189 for i in range(len(self.stop_deferreds)):
189 for i in range(len(self.stop_deferreds)):
190 d = self.stop_deferreds.pop()
190 d = self.stop_deferreds.pop()
191 d.callback(data)
191 d.callback(data)
192 return data
192 return data
193
193
194 def signal(self, sig):
194 def signal(self, sig):
195 """Signal the process.
195 """Signal the process.
196
196
197 Return a semi-meaningless deferred after signaling the process.
197 Return a semi-meaningless deferred after signaling the process.
198
198
199 Parameters
199 Parameters
200 ----------
200 ----------
201 sig : str or int
201 sig : str or int
202 'KILL', 'INT', etc., or any signal number
202 'KILL', 'INT', etc., or any signal number
203 """
203 """
204 return defer.fail(
204 return defer.fail(
205 Failure(NotImplementedError(
205 Failure(NotImplementedError(
206 'signal must be implemented in a subclass')
206 'signal must be implemented in a subclass')
207 )
207 )
208 )
208 )
209
209
210
210
211 #-----------------------------------------------------------------------------
211 #-----------------------------------------------------------------------------
212 # Local process launchers
212 # Local process launchers
213 #-----------------------------------------------------------------------------
213 #-----------------------------------------------------------------------------
214
214
215
215
216 class LocalProcessLauncherProtocol(ProcessProtocol):
216 class LocalProcessLauncherProtocol(ProcessProtocol):
217 """A ProcessProtocol to go with the LocalProcessLauncher."""
217 """A ProcessProtocol to go with the LocalProcessLauncher."""
218
218
219 def __init__(self, process_launcher):
219 def __init__(self, process_launcher):
220 self.process_launcher = process_launcher
220 self.process_launcher = process_launcher
221 self.pid = None
221 self.pid = None
222
222
223 def connectionMade(self):
223 def connectionMade(self):
224 self.pid = self.transport.pid
224 self.pid = self.transport.pid
225 self.process_launcher.notify_start(self.transport.pid)
225 self.process_launcher.notify_start(self.transport.pid)
226
226
227 def processEnded(self, status):
227 def processEnded(self, status):
228 value = status.value
228 value = status.value
229 if isinstance(value, ProcessDone):
229 if isinstance(value, ProcessDone):
230 self.process_launcher.notify_stop(
230 self.process_launcher.notify_stop(
231 {'exit_code':0,
231 {'exit_code':0,
232 'signal':None,
232 'signal':None,
233 'status':None,
233 'status':None,
234 'pid':self.pid
234 'pid':self.pid
235 }
235 }
236 )
236 )
237 elif isinstance(value, ProcessTerminated):
237 elif isinstance(value, ProcessTerminated):
238 self.process_launcher.notify_stop(
238 self.process_launcher.notify_stop(
239 {'exit_code':value.exitCode,
239 {'exit_code':value.exitCode,
240 'signal':value.signal,
240 'signal':value.signal,
241 'status':value.status,
241 'status':value.status,
242 'pid':self.pid
242 'pid':self.pid
243 }
243 }
244 )
244 )
245 else:
245 else:
246 raise UnknownStatus("Unknown exit status, this is probably a "
246 raise UnknownStatus("Unknown exit status, this is probably a "
247 "bug in Twisted")
247 "bug in Twisted")
248
248
249 def outReceived(self, data):
249 def outReceived(self, data):
250 log.msg(data)
250 log.msg(data)
251
251
252 def errReceived(self, data):
252 def errReceived(self, data):
253 log.err(data)
253 log.err(data)
254
254
255
255
256 class LocalProcessLauncher(BaseLauncher):
256 class LocalProcessLauncher(BaseLauncher):
257 """Start and stop an external process in an asynchronous manner.
257 """Start and stop an external process in an asynchronous manner.
258
258
259 This will launch the external process with a working directory of
259 This will launch the external process with a working directory of
260 ``self.work_dir``.
260 ``self.work_dir``.
261 """
261 """
262
262
263 # This is used to to construct self.args, which is passed to
263 # This is used to to construct self.args, which is passed to
264 # spawnProcess.
264 # spawnProcess.
265 cmd_and_args = List([])
265 cmd_and_args = List([])
266
266
267 def __init__(self, work_dir=u'', config=None):
267 def __init__(self, work_dir=u'', config=None):
268 super(LocalProcessLauncher, self).__init__(
268 super(LocalProcessLauncher, self).__init__(
269 work_dir=work_dir, config=config
269 work_dir=work_dir, config=config
270 )
270 )
271 self.process_protocol = None
271 self.process_protocol = None
272 self.start_deferred = None
272 self.start_deferred = None
273
273
274 def find_args(self):
274 def find_args(self):
275 return self.cmd_and_args
275 return self.cmd_and_args
276
276
277 def start(self):
277 def start(self):
278 if self.state == 'before':
278 if self.state == 'before':
279 self.process_protocol = LocalProcessLauncherProtocol(self)
279 self.process_protocol = LocalProcessLauncherProtocol(self)
280 self.start_deferred = defer.Deferred()
280 self.start_deferred = defer.Deferred()
281 self.process_transport = reactor.spawnProcess(
281 self.process_transport = reactor.spawnProcess(
282 self.process_protocol,
282 self.process_protocol,
283 str(self.args[0]), # twisted expects these to be str, not unicode
283 str(self.args[0]), # twisted expects these to be str, not unicode
284 [str(a) for a in self.args], # str expected, not unicode
284 [str(a) for a in self.args], # str expected, not unicode
285 env=os.environ,
285 env=os.environ,
286 path=self.work_dir # start in the work_dir
286 path=self.work_dir # start in the work_dir
287 )
287 )
288 return self.start_deferred
288 return self.start_deferred
289 else:
289 else:
290 s = 'The process was already started and has state: %r' % self.state
290 s = 'The process was already started and has state: %r' % self.state
291 return defer.fail(ProcessStateError(s))
291 return defer.fail(ProcessStateError(s))
292
292
293 def notify_start(self, data):
293 def notify_start(self, data):
294 super(LocalProcessLauncher, self).notify_start(data)
294 super(LocalProcessLauncher, self).notify_start(data)
295 self.start_deferred.callback(data)
295 self.start_deferred.callback(data)
296
296
297 def stop(self):
297 def stop(self):
298 return self.interrupt_then_kill()
298 return self.interrupt_then_kill()
299
299
300 @make_deferred
300 @make_deferred
301 def signal(self, sig):
301 def signal(self, sig):
302 if self.state == 'running':
302 if self.state == 'running':
303 self.process_transport.signalProcess(sig)
303 self.process_transport.signalProcess(sig)
304
304
305 @inlineCallbacks
305 @inlineCallbacks
306 def interrupt_then_kill(self, delay=2.0):
306 def interrupt_then_kill(self, delay=2.0):
307 """Send INT, wait a delay and then send KILL."""
307 """Send INT, wait a delay and then send KILL."""
308 yield self.signal('INT')
308 yield self.signal('INT')
309 yield sleep_deferred(delay)
309 yield sleep_deferred(delay)
310 yield self.signal('KILL')
310 yield self.signal('KILL')
311
311
312
312
313 class LocalControllerLauncher(LocalProcessLauncher):
313 class LocalControllerLauncher(LocalProcessLauncher):
314 """Launch a controller as a regular external process."""
314 """Launch a controller as a regular external process."""
315
315
316 controller_cmd = List(ipcontroller_cmd_argv, config=True)
316 controller_cmd = List(ipcontroller_cmd_argv, config=True)
317 # Command line arguments to ipcontroller.
317 # Command line arguments to ipcontroller.
318 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
318 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
319
319
320 def find_args(self):
320 def find_args(self):
321 return self.controller_cmd + self.controller_args
321 return self.controller_cmd + self.controller_args
322
322
323 def start(self, cluster_dir):
323 def start(self, cluster_dir):
324 """Start the controller by cluster_dir."""
324 """Start the controller by cluster_dir."""
325 self.controller_args.extend(['--cluster-dir', cluster_dir])
325 self.controller_args.extend(['--cluster-dir', cluster_dir])
326 self.cluster_dir = unicode(cluster_dir)
326 self.cluster_dir = unicode(cluster_dir)
327 log.msg("Starting LocalControllerLauncher: %r" % self.args)
327 log.msg("Starting LocalControllerLauncher: %r" % self.args)
328 return super(LocalControllerLauncher, self).start()
328 return super(LocalControllerLauncher, self).start()
329
329
330
330
331 class LocalEngineLauncher(LocalProcessLauncher):
331 class LocalEngineLauncher(LocalProcessLauncher):
332 """Launch a single engine as a regular externall process."""
332 """Launch a single engine as a regular externall process."""
333
333
334 engine_cmd = List(ipengine_cmd_argv, config=True)
334 engine_cmd = List(ipengine_cmd_argv, config=True)
335 # Command line arguments for ipengine.
335 # Command line arguments for ipengine.
336 engine_args = List(
336 engine_args = List(
337 ['--log-to-file','--log-level', '40'], config=True
337 ['--log-to-file','--log-level', '40'], config=True
338 )
338 )
339
339
340 def find_args(self):
340 def find_args(self):
341 return self.engine_cmd + self.engine_args
341 return self.engine_cmd + self.engine_args
342
342
343 def start(self, cluster_dir):
343 def start(self, cluster_dir):
344 """Start the engine by cluster_dir."""
344 """Start the engine by cluster_dir."""
345 self.engine_args.extend(['--cluster-dir', cluster_dir])
345 self.engine_args.extend(['--cluster-dir', cluster_dir])
346 self.cluster_dir = unicode(cluster_dir)
346 self.cluster_dir = unicode(cluster_dir)
347 return super(LocalEngineLauncher, self).start()
347 return super(LocalEngineLauncher, self).start()
348
348
349
349
350 class LocalEngineSetLauncher(BaseLauncher):
350 class LocalEngineSetLauncher(BaseLauncher):
351 """Launch a set of engines as regular external processes."""
351 """Launch a set of engines as regular external processes."""
352
352
353 # Command line arguments for ipengine.
353 # Command line arguments for ipengine.
354 engine_args = List(
354 engine_args = List(
355 ['--log-to-file','--log-level', '40'], config=True
355 ['--log-to-file','--log-level', '40'], config=True
356 )
356 )
357
357
358 def __init__(self, work_dir=u'', config=None):
358 def __init__(self, work_dir=u'', config=None):
359 super(LocalEngineSetLauncher, self).__init__(
359 super(LocalEngineSetLauncher, self).__init__(
360 work_dir=work_dir, config=config
360 work_dir=work_dir, config=config
361 )
361 )
362 self.launchers = []
362 self.launchers = []
363
363
364 def start(self, n, cluster_dir):
364 def start(self, n, cluster_dir):
365 """Start n engines by profile or cluster_dir."""
365 """Start n engines by profile or cluster_dir."""
366 self.cluster_dir = unicode(cluster_dir)
366 self.cluster_dir = unicode(cluster_dir)
367 dlist = []
367 dlist = []
368 for i in range(n):
368 for i in range(n):
369 el = LocalEngineLauncher(work_dir=self.work_dir, config=self.config)
369 el = LocalEngineLauncher(work_dir=self.work_dir, config=self.config)
370 # Copy the engine args over to each engine launcher.
370 # Copy the engine args over to each engine launcher.
371 import copy
371 import copy
372 el.engine_args = copy.deepcopy(self.engine_args)
372 el.engine_args = copy.deepcopy(self.engine_args)
373 d = el.start(cluster_dir)
373 d = el.start(cluster_dir)
374 if i==0:
374 if i==0:
375 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
375 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
376 self.launchers.append(el)
376 self.launchers.append(el)
377 dlist.append(d)
377 dlist.append(d)
378 # The consumeErrors here could be dangerous
378 # The consumeErrors here could be dangerous
379 dfinal = gatherBoth(dlist, consumeErrors=True)
379 dfinal = gatherBoth(dlist, consumeErrors=True)
380 dfinal.addCallback(self.notify_start)
380 dfinal.addCallback(self.notify_start)
381 return dfinal
381 return dfinal
382
382
383 def find_args(self):
383 def find_args(self):
384 return ['engine set']
384 return ['engine set']
385
385
386 def signal(self, sig):
386 def signal(self, sig):
387 dlist = []
387 dlist = []
388 for el in self.launchers:
388 for el in self.launchers:
389 d = el.signal(sig)
389 d = el.signal(sig)
390 dlist.append(d)
390 dlist.append(d)
391 dfinal = gatherBoth(dlist, consumeErrors=True)
391 dfinal = gatherBoth(dlist, consumeErrors=True)
392 return dfinal
392 return dfinal
393
393
394 def interrupt_then_kill(self, delay=1.0):
394 def interrupt_then_kill(self, delay=1.0):
395 dlist = []
395 dlist = []
396 for el in self.launchers:
396 for el in self.launchers:
397 d = el.interrupt_then_kill(delay)
397 d = el.interrupt_then_kill(delay)
398 dlist.append(d)
398 dlist.append(d)
399 dfinal = gatherBoth(dlist, consumeErrors=True)
399 dfinal = gatherBoth(dlist, consumeErrors=True)
400 return dfinal
400 return dfinal
401
401
402 def stop(self):
402 def stop(self):
403 return self.interrupt_then_kill()
403 return self.interrupt_then_kill()
404
404
405 def observe_stop(self):
405 def observe_stop(self):
406 dlist = [el.observe_stop() for el in self.launchers]
406 dlist = [el.observe_stop() for el in self.launchers]
407 dfinal = gatherBoth(dlist, consumeErrors=False)
407 dfinal = gatherBoth(dlist, consumeErrors=False)
408 dfinal.addCallback(self.notify_stop)
408 dfinal.addCallback(self.notify_stop)
409 return dfinal
409 return dfinal
410
410
411
411
412 #-----------------------------------------------------------------------------
412 #-----------------------------------------------------------------------------
413 # MPIExec launchers
413 # MPIExec launchers
414 #-----------------------------------------------------------------------------
414 #-----------------------------------------------------------------------------
415
415
416
416
417 class MPIExecLauncher(LocalProcessLauncher):
417 class MPIExecLauncher(LocalProcessLauncher):
418 """Launch an external process using mpiexec."""
418 """Launch an external process using mpiexec."""
419
419
420 # The mpiexec command to use in starting the process.
420 # The mpiexec command to use in starting the process.
421 mpi_cmd = List(['mpiexec'], config=True)
421 mpi_cmd = List(['mpiexec'], config=True)
422 # The command line arguments to pass to mpiexec.
422 # The command line arguments to pass to mpiexec.
423 mpi_args = List([], config=True)
423 mpi_args = List([], config=True)
424 # The program to start using mpiexec.
424 # The program to start using mpiexec.
425 program = List(['date'], config=True)
425 program = List(['date'], config=True)
426 # The command line argument to the program.
426 # The command line argument to the program.
427 program_args = List([], config=True)
427 program_args = List([], config=True)
428 # The number of instances of the program to start.
428 # The number of instances of the program to start.
429 n = Int(1, config=True)
429 n = Int(1, config=True)
430
430
431 def find_args(self):
431 def find_args(self):
432 """Build self.args using all the fields."""
432 """Build self.args using all the fields."""
433 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
433 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
434 self.program + self.program_args
434 self.program + self.program_args
435
435
436 def start(self, n):
436 def start(self, n):
437 """Start n instances of the program using mpiexec."""
437 """Start n instances of the program using mpiexec."""
438 self.n = n
438 self.n = n
439 return super(MPIExecLauncher, self).start()
439 return super(MPIExecLauncher, self).start()
440
440
441
441
442 class MPIExecControllerLauncher(MPIExecLauncher):
442 class MPIExecControllerLauncher(MPIExecLauncher):
443 """Launch a controller using mpiexec."""
443 """Launch a controller using mpiexec."""
444
444
445 controller_cmd = List(ipcontroller_cmd_argv, config=True)
445 controller_cmd = List(ipcontroller_cmd_argv, config=True)
446 # Command line arguments to ipcontroller.
446 # Command line arguments to ipcontroller.
447 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
447 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
448 n = Int(1, config=False)
448 n = Int(1, config=False)
449
449
450 def start(self, cluster_dir):
450 def start(self, cluster_dir):
451 """Start the controller by cluster_dir."""
451 """Start the controller by cluster_dir."""
452 self.controller_args.extend(['--cluster-dir', cluster_dir])
452 self.controller_args.extend(['--cluster-dir', cluster_dir])
453 self.cluster_dir = unicode(cluster_dir)
453 self.cluster_dir = unicode(cluster_dir)
454 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
454 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
455 return super(MPIExecControllerLauncher, self).start(1)
455 return super(MPIExecControllerLauncher, self).start(1)
456
456
457 def find_args(self):
457 def find_args(self):
458 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
458 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
459 self.controller_cmd + self.controller_args
459 self.controller_cmd + self.controller_args
460
460
461
461
462 class MPIExecEngineSetLauncher(MPIExecLauncher):
462 class MPIExecEngineSetLauncher(MPIExecLauncher):
463
463
464 engine_cmd = List(ipengine_cmd_argv, config=True)
464 engine_cmd = List(ipengine_cmd_argv, config=True)
465 # Command line arguments for ipengine.
465 # Command line arguments for ipengine.
466 engine_args = List(
466 engine_args = List(
467 ['--log-to-file','--log-level', '40'], config=True
467 ['--log-to-file','--log-level', '40'], config=True
468 )
468 )
469 n = Int(1, config=True)
469 n = Int(1, config=True)
470
470
471 def start(self, n, cluster_dir):
471 def start(self, n, cluster_dir):
472 """Start n engines by profile or cluster_dir."""
472 """Start n engines by profile or cluster_dir."""
473 self.engine_args.extend(['--cluster-dir', cluster_dir])
473 self.engine_args.extend(['--cluster-dir', cluster_dir])
474 self.cluster_dir = unicode(cluster_dir)
474 self.cluster_dir = unicode(cluster_dir)
475 self.n = n
475 self.n = n
476 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
476 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
477 return super(MPIExecEngineSetLauncher, self).start(n)
477 return super(MPIExecEngineSetLauncher, self).start(n)
478
478
479 def find_args(self):
479 def find_args(self):
480 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
480 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
481 self.engine_cmd + self.engine_args
481 self.engine_cmd + self.engine_args
482
482
483
483
484 #-----------------------------------------------------------------------------
484 #-----------------------------------------------------------------------------
485 # SSH launchers
485 # SSH launchers
486 #-----------------------------------------------------------------------------
486 #-----------------------------------------------------------------------------
487
487
488 # TODO: Get SSH Launcher working again.
488 # TODO: Get SSH Launcher working again.
489
489
490 class SSHLauncher(BaseLauncher):
490 class SSHLauncher(BaseLauncher):
491 """A minimal launcher for ssh.
491 """A minimal launcher for ssh.
492
492
493 To be useful this will probably have to be extended to use the ``sshx``
493 To be useful this will probably have to be extended to use the ``sshx``
494 idea for environment variables. There could be other things this needs
494 idea for environment variables. There could be other things this needs
495 as well.
495 as well.
496 """
496 """
497
497
498 ssh_cmd = List(['ssh'], config=True)
498 ssh_cmd = List(['ssh'], config=True)
499 ssh_args = List([], config=True)
499 ssh_args = List([], config=True)
500 program = List(['date'], config=True)
500 program = List(['date'], config=True)
501 program_args = List([], config=True)
501 program_args = List([], config=True)
502 hostname = Str('', config=True)
502 hostname = Str('', config=True)
503 user = Str('', config=True)
503 user = Str('', config=True)
504 location = Str('')
504 location = Str('')
505
505
506 def _hostname_changed(self, name, old, new):
506 def _hostname_changed(self, name, old, new):
507 self.location = '%s@%s' % (self.user, new)
507 self.location = '%s@%s' % (self.user, new)
508
508
509 def _user_changed(self, name, old, new):
509 def _user_changed(self, name, old, new):
510 self.location = '%s@%s' % (new, self.hostname)
510 self.location = '%s@%s' % (new, self.hostname)
511
511
512 def find_args(self):
512 def find_args(self):
513 return self.ssh_cmd + self.ssh_args + [self.location] + \
513 return self.ssh_cmd + self.ssh_args + [self.location] + \
514 self.program + self.program_args
514 self.program + self.program_args
515
515
516 def start(self, n, hostname=None, user=None):
516 def start(self, n, hostname=None, user=None):
517 if hostname is not None:
517 if hostname is not None:
518 self.hostname = hostname
518 self.hostname = hostname
519 if user is not None:
519 if user is not None:
520 self.user = user
520 self.user = user
521 return super(SSHLauncher, self).start()
521 return super(SSHLauncher, self).start()
522
522
523
523
524 class SSHControllerLauncher(SSHLauncher):
524 class SSHControllerLauncher(SSHLauncher):
525 pass
525 pass
526
526
527
527
528 class SSHEngineSetLauncher(BaseLauncher):
528 class SSHEngineSetLauncher(BaseLauncher):
529 pass
529 pass
530
530
531
531
532 #-----------------------------------------------------------------------------
532 #-----------------------------------------------------------------------------
533 # Windows HPC Server 2008 scheduler launchers
533 # Windows HPC Server 2008 scheduler launchers
534 #-----------------------------------------------------------------------------
534 #-----------------------------------------------------------------------------
535
535
536
536
537 # This is only used on Windows.
537 # This is only used on Windows.
538 def find_job_cmd():
538 def find_job_cmd():
539 if os.name=='nt':
539 if os.name=='nt':
540 try:
540 try:
541 return find_cmd('job')
541 return find_cmd('job')
542 except FindCmdError:
542 except FindCmdError:
543 return 'job'
543 return 'job'
544 else:
544 else:
545 return 'job'
545 return 'job'
546
546
547
547
548 class WindowsHPCLauncher(BaseLauncher):
548 class WindowsHPCLauncher(BaseLauncher):
549
549
550 # A regular expression used to get the job id from the output of the
550 # A regular expression used to get the job id from the output of the
551 # submit_command.
551 # submit_command.
552 job_id_regexp = Str(r'\d+', config=True)
552 job_id_regexp = Str(r'\d+', config=True)
553 # The filename of the instantiated job script.
553 # The filename of the instantiated job script.
554 job_file_name = Unicode(u'ipython_job.xml', config=True)
554 job_file_name = Unicode(u'ipython_job.xml', config=True)
555 # The full path to the instantiated job script. This gets made dynamically
555 # The full path to the instantiated job script. This gets made dynamically
556 # by combining the work_dir with the job_file_name.
556 # by combining the work_dir with the job_file_name.
557 job_file = Unicode(u'')
557 job_file = Unicode(u'')
558 # The hostname of the scheduler to submit the job to
558 # The hostname of the scheduler to submit the job to
559 scheduler = Str('', config=True)
559 scheduler = Str('', config=True)
560 job_cmd = Str(find_job_cmd(), config=True)
560 job_cmd = Str(find_job_cmd(), config=True)
561
561
562 def __init__(self, work_dir=u'', config=None):
562 def __init__(self, work_dir=u'', config=None):
563 super(WindowsHPCLauncher, self).__init__(
563 super(WindowsHPCLauncher, self).__init__(
564 work_dir=work_dir, config=config
564 work_dir=work_dir, config=config
565 )
565 )
566
566
567 @property
567 @property
568 def job_file(self):
568 def job_file(self):
569 return os.path.join(self.work_dir, self.job_file_name)
569 return os.path.join(self.work_dir, self.job_file_name)
570
570
571 def write_job_file(self, n):
571 def write_job_file(self, n):
572 raise NotImplementedError("Implement write_job_file in a subclass.")
572 raise NotImplementedError("Implement write_job_file in a subclass.")
573
573
574 def find_args(self):
574 def find_args(self):
575 return ['job.exe']
575 return ['job.exe']
576
576
577 def parse_job_id(self, output):
577 def parse_job_id(self, output):
578 """Take the output of the submit command and return the job id."""
578 """Take the output of the submit command and return the job id."""
579 m = re.search(self.job_id_regexp, output)
579 m = re.search(self.job_id_regexp, output)
580 if m is not None:
580 if m is not None:
581 job_id = m.group()
581 job_id = m.group()
582 else:
582 else:
583 raise LauncherError("Job id couldn't be determined: %s" % output)
583 raise LauncherError("Job id couldn't be determined: %s" % output)
584 self.job_id = job_id
584 self.job_id = job_id
585 log.msg('Job started with job id: %r' % job_id)
585 log.msg('Job started with job id: %r' % job_id)
586 return job_id
586 return job_id
587
587
588 @inlineCallbacks
588 @inlineCallbacks
589 def start(self, n):
589 def start(self, n):
590 """Start n copies of the process using the Win HPC job scheduler."""
590 """Start n copies of the process using the Win HPC job scheduler."""
591 self.write_job_file(n)
591 self.write_job_file(n)
592 args = [
592 args = [
593 'submit',
593 'submit',
594 '/jobfile:%s' % self.job_file,
594 '/jobfile:%s' % self.job_file,
595 '/scheduler:%s' % self.scheduler
595 '/scheduler:%s' % self.scheduler
596 ]
596 ]
597 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
597 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
598 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
598 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
599 output = yield getProcessOutput(str(self.job_cmd),
599 output = yield getProcessOutput(str(self.job_cmd),
600 [str(a) for a in args],
600 [str(a) for a in args],
601 env=dict((str(k),str(v)) for k,v in os.environ.items()),
601 env=dict((str(k),str(v)) for k,v in os.environ.items()),
602 path=self.work_dir
602 path=self.work_dir
603 )
603 )
604 job_id = self.parse_job_id(output)
604 job_id = self.parse_job_id(output)
605 self.notify_start(job_id)
605 self.notify_start(job_id)
606 defer.returnValue(job_id)
606 defer.returnValue(job_id)
607
607
608 @inlineCallbacks
608 @inlineCallbacks
609 def stop(self):
609 def stop(self):
610 args = [
610 args = [
611 'cancel',
611 'cancel',
612 self.job_id,
612 self.job_id,
613 '/scheduler:%s' % self.scheduler
613 '/scheduler:%s' % self.scheduler
614 ]
614 ]
615 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
615 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
616 try:
616 try:
617 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
617 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
618 output = yield getProcessOutput(str(self.job_cmd),
618 output = yield getProcessOutput(str(self.job_cmd),
619 [str(a) for a in args],
619 [str(a) for a in args],
620 env=dict((str(k),str(v)) for k,v in os.environ.items()),
620 env=dict((str(k),str(v)) for k,v in os.environ.iteritems()),
621 path=self.work_dir
621 path=self.work_dir
622 )
622 )
623 except:
623 except:
624 output = 'The job already appears to be stoppped: %r' % self.job_id
624 output = 'The job already appears to be stoppped: %r' % self.job_id
625 self.notify_stop(output) # Pass the output of the kill cmd
625 self.notify_stop(output) # Pass the output of the kill cmd
626 defer.returnValue(output)
626 defer.returnValue(output)
627
627
628
628
629 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
629 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
630
630
631 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
631 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
632 extra_args = List([], config=False)
632 extra_args = List([], config=False)
633
633
634 def write_job_file(self, n):
634 def write_job_file(self, n):
635 job = IPControllerJob(config=self.config)
635 job = IPControllerJob(config=self.config)
636
636
637 t = IPControllerTask(config=self.config)
637 t = IPControllerTask(config=self.config)
638 # The tasks work directory is *not* the actual work directory of
638 # The tasks work directory is *not* the actual work directory of
639 # the controller. It is used as the base path for the stdout/stderr
639 # the controller. It is used as the base path for the stdout/stderr
640 # files that the scheduler redirects to.
640 # files that the scheduler redirects to.
641 t.work_directory = self.cluster_dir
641 t.work_directory = self.cluster_dir
642 # Add the --cluster-dir and from self.start().
642 # Add the --cluster-dir and from self.start().
643 t.controller_args.extend(self.extra_args)
643 t.controller_args.extend(self.extra_args)
644 job.add_task(t)
644 job.add_task(t)
645
645
646 log.msg("Writing job description file: %s" % self.job_file)
646 log.msg("Writing job description file: %s" % self.job_file)
647 job.write(self.job_file)
647 job.write(self.job_file)
648
648
649 @property
649 @property
650 def job_file(self):
650 def job_file(self):
651 return os.path.join(self.cluster_dir, self.job_file_name)
651 return os.path.join(self.cluster_dir, self.job_file_name)
652
652
653 def start(self, cluster_dir):
653 def start(self, cluster_dir):
654 """Start the controller by cluster_dir."""
654 """Start the controller by cluster_dir."""
655 self.extra_args = ['--cluster-dir', cluster_dir]
655 self.extra_args = ['--cluster-dir', cluster_dir]
656 self.cluster_dir = unicode(cluster_dir)
656 self.cluster_dir = unicode(cluster_dir)
657 return super(WindowsHPCControllerLauncher, self).start(1)
657 return super(WindowsHPCControllerLauncher, self).start(1)
658
658
659
659
660 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
660 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
661
661
662 job_file_name = Unicode(u'ipengineset_job.xml', config=True)
662 job_file_name = Unicode(u'ipengineset_job.xml', config=True)
663 extra_args = List([], config=False)
663 extra_args = List([], config=False)
664
664
665 def write_job_file(self, n):
665 def write_job_file(self, n):
666 job = IPEngineSetJob(config=self.config)
666 job = IPEngineSetJob(config=self.config)
667
667
668 for i in range(n):
668 for i in range(n):
669 t = IPEngineTask(config=self.config)
669 t = IPEngineTask(config=self.config)
670 # The tasks work directory is *not* the actual work directory of
670 # The tasks work directory is *not* the actual work directory of
671 # the engine. It is used as the base path for the stdout/stderr
671 # the engine. It is used as the base path for the stdout/stderr
672 # files that the scheduler redirects to.
672 # files that the scheduler redirects to.
673 t.work_directory = self.cluster_dir
673 t.work_directory = self.cluster_dir
674 # Add the --cluster-dir and from self.start().
674 # Add the --cluster-dir and from self.start().
675 t.engine_args.extend(self.extra_args)
675 t.engine_args.extend(self.extra_args)
676 job.add_task(t)
676 job.add_task(t)
677
677
678 log.msg("Writing job description file: %s" % self.job_file)
678 log.msg("Writing job description file: %s" % self.job_file)
679 job.write(self.job_file)
679 job.write(self.job_file)
680
680
681 @property
681 @property
682 def job_file(self):
682 def job_file(self):
683 return os.path.join(self.cluster_dir, self.job_file_name)
683 return os.path.join(self.cluster_dir, self.job_file_name)
684
684
685 def start(self, n, cluster_dir):
685 def start(self, n, cluster_dir):
686 """Start the controller by cluster_dir."""
686 """Start the controller by cluster_dir."""
687 self.extra_args = ['--cluster-dir', cluster_dir]
687 self.extra_args = ['--cluster-dir', cluster_dir]
688 self.cluster_dir = unicode(cluster_dir)
688 self.cluster_dir = unicode(cluster_dir)
689 return super(WindowsHPCEngineSetLauncher, self).start(n)
689 return super(WindowsHPCEngineSetLauncher, self).start(n)
690
690
691
691
692 #-----------------------------------------------------------------------------
692 #-----------------------------------------------------------------------------
693 # Batch (PBS) system launchers
693 # Batch (PBS) system launchers
694 #-----------------------------------------------------------------------------
694 #-----------------------------------------------------------------------------
695
695
696 # TODO: Get PBS launcher working again.
696 # TODO: Get PBS launcher working again.
697
697
698 class BatchSystemLauncher(BaseLauncher):
698 class BatchSystemLauncher(BaseLauncher):
699 """Launch an external process using a batch system.
699 """Launch an external process using a batch system.
700
700
701 This class is designed to work with UNIX batch systems like PBS, LSF,
701 This class is designed to work with UNIX batch systems like PBS, LSF,
702 GridEngine, etc. The overall model is that there are different commands
702 GridEngine, etc. The overall model is that there are different commands
703 like qsub, qdel, etc. that handle the starting and stopping of the process.
703 like qsub, qdel, etc. that handle the starting and stopping of the process.
704
704
705 This class also has the notion of a batch script. The ``batch_template``
705 This class also has the notion of a batch script. The ``batch_template``
706 attribute can be set to a string that is a template for the batch script.
706 attribute can be set to a string that is a template for the batch script.
707 This template is instantiated using Itpl. Thus the template can use
707 This template is instantiated using Itpl. Thus the template can use
708 ${n} fot the number of instances. Subclasses can add additional variables
708 ${n} fot the number of instances. Subclasses can add additional variables
709 to the template dict.
709 to the template dict.
710 """
710 """
711
711
712 # Subclasses must fill these in. See PBSEngineSet
712 # Subclasses must fill these in. See PBSEngineSet
713 # The name of the command line program used to submit jobs.
713 # The name of the command line program used to submit jobs.
714 submit_command = Str('', config=True)
714 submit_command = Str('', config=True)
715 # The name of the command line program used to delete jobs.
715 # The name of the command line program used to delete jobs.
716 delete_command = Str('', config=True)
716 delete_command = Str('', config=True)
717 # A regular expression used to get the job id from the output of the
717 # A regular expression used to get the job id from the output of the
718 # submit_command.
718 # submit_command.
719 job_id_regexp = Str('', config=True)
719 job_id_regexp = Str('', config=True)
720 # The string that is the batch script template itself.
720 # The string that is the batch script template itself.
721 batch_template = Str('', config=True)
721 batch_template = Str('', config=True)
722 # The filename of the instantiated batch script.
722 # The filename of the instantiated batch script.
723 batch_file_name = Unicode(u'batch_script', config=True)
723 batch_file_name = Unicode(u'batch_script', config=True)
724 # The full path to the instantiated batch script.
724 # The full path to the instantiated batch script.
725 batch_file = Unicode(u'')
725 batch_file = Unicode(u'')
726
726
727 def __init__(self, work_dir=u'', config=None):
727 def __init__(self, work_dir=u'', config=None):
728 super(BatchSystemLauncher, self).__init__(
728 super(BatchSystemLauncher, self).__init__(
729 work_dir=work_dir, config=config
729 work_dir=work_dir, config=config
730 )
730 )
731 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
731 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
732 self.context = {}
732 self.context = {}
733
733
734 def parse_job_id(self, output):
734 def parse_job_id(self, output):
735 """Take the output of the submit command and return the job id."""
735 """Take the output of the submit command and return the job id."""
736 m = re.match(self.job_id_regexp, output)
736 m = re.match(self.job_id_regexp, output)
737 if m is not None:
737 if m is not None:
738 job_id = m.group()
738 job_id = m.group()
739 else:
739 else:
740 raise LauncherError("Job id couldn't be determined: %s" % output)
740 raise LauncherError("Job id couldn't be determined: %s" % output)
741 self.job_id = job_id
741 self.job_id = job_id
742 log.msg('Job started with job id: %r' % job_id)
742 log.msg('Job started with job id: %r' % job_id)
743 return job_id
743 return job_id
744
744
745 def write_batch_script(self, n):
745 def write_batch_script(self, n):
746 """Instantiate and write the batch script to the work_dir."""
746 """Instantiate and write the batch script to the work_dir."""
747 self.context['n'] = n
747 self.context['n'] = n
748 script_as_string = Itpl.itplns(self.batch_template, self.context)
748 script_as_string = Itpl.itplns(self.batch_template, self.context)
749 log.msg('Writing instantiated batch script: %s' % self.batch_file)
749 log.msg('Writing instantiated batch script: %s' % self.batch_file)
750 f = open(self.batch_file, 'w')
750 f = open(self.batch_file, 'w')
751 f.write(script_as_string)
751 f.write(script_as_string)
752 f.close()
752 f.close()
753
753
754 @inlineCallbacks
754 @inlineCallbacks
755 def start(self, n):
755 def start(self, n):
756 """Start n copies of the process using a batch system."""
756 """Start n copies of the process using a batch system."""
757 self.write_batch_script(n)
757 self.write_batch_script(n)
758 output = yield getProcessOutput(self.submit_command,
758 output = yield getProcessOutput(self.submit_command,
759 [self.batch_file], env=os.environ)
759 [self.batch_file], env=os.environ)
760 job_id = self.parse_job_id(output)
760 job_id = self.parse_job_id(output)
761 self.notify_start(job_id)
761 self.notify_start(job_id)
762 defer.returnValue(job_id)
762 defer.returnValue(job_id)
763
763
764 @inlineCallbacks
764 @inlineCallbacks
765 def stop(self):
765 def stop(self):
766 output = yield getProcessOutput(self.delete_command,
766 output = yield getProcessOutput(self.delete_command,
767 [self.job_id], env=os.environ
767 [self.job_id], env=os.environ
768 )
768 )
769 self.notify_stop(output) # Pass the output of the kill cmd
769 self.notify_stop(output) # Pass the output of the kill cmd
770 defer.returnValue(output)
770 defer.returnValue(output)
771
771
772
772
773 class PBSLauncher(BatchSystemLauncher):
773 class PBSLauncher(BatchSystemLauncher):
774 """A BatchSystemLauncher subclass for PBS."""
774 """A BatchSystemLauncher subclass for PBS."""
775
775
776 submit_command = Str('qsub', config=True)
776 submit_command = Str('qsub', config=True)
777 delete_command = Str('qdel', config=True)
777 delete_command = Str('qdel', config=True)
778 job_id_regexp = Str(r'\d+', config=True)
778 job_id_regexp = Str(r'\d+', config=True)
779 batch_template = Str('', config=True)
779 batch_template = Str('', config=True)
780 batch_file_name = Unicode(u'pbs_batch_script', config=True)
780 batch_file_name = Unicode(u'pbs_batch_script', config=True)
781 batch_file = Unicode(u'')
781 batch_file = Unicode(u'')
782
782
783
783
784 class PBSControllerLauncher(PBSLauncher):
784 class PBSControllerLauncher(PBSLauncher):
785 """Launch a controller using PBS."""
785 """Launch a controller using PBS."""
786
786
787 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
787 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
788
788
789 def start(self, cluster_dir):
789 def start(self, cluster_dir):
790 """Start the controller by profile or cluster_dir."""
790 """Start the controller by profile or cluster_dir."""
791 # Here we save profile and cluster_dir in the context so they
791 # Here we save profile and cluster_dir in the context so they
792 # can be used in the batch script template as ${profile} and
792 # can be used in the batch script template as ${profile} and
793 # ${cluster_dir}
793 # ${cluster_dir}
794 self.context['cluster_dir'] = cluster_dir
794 self.context['cluster_dir'] = cluster_dir
795 self.cluster_dir = unicode(cluster_dir)
795 self.cluster_dir = unicode(cluster_dir)
796 log.msg("Starting PBSControllerLauncher: %r" % self.args)
796 log.msg("Starting PBSControllerLauncher: %r" % self.args)
797 return super(PBSControllerLauncher, self).start(1)
797 return super(PBSControllerLauncher, self).start(1)
798
798
799
799
800 class PBSEngineSetLauncher(PBSLauncher):
800 class PBSEngineSetLauncher(PBSLauncher):
801
801
802 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
802 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
803
803
804 def start(self, n, cluster_dir):
804 def start(self, n, cluster_dir):
805 """Start n engines by profile or cluster_dir."""
805 """Start n engines by profile or cluster_dir."""
806 self.program_args.extend(['--cluster-dir', cluster_dir])
806 self.program_args.extend(['--cluster-dir', cluster_dir])
807 self.cluster_dir = unicode(cluster_dir)
807 self.cluster_dir = unicode(cluster_dir)
808 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
808 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
809 return super(PBSEngineSetLauncher, self).start(n)
809 return super(PBSEngineSetLauncher, self).start(n)
810
810
811
811
812 #-----------------------------------------------------------------------------
812 #-----------------------------------------------------------------------------
813 # A launcher for ipcluster itself!
813 # A launcher for ipcluster itself!
814 #-----------------------------------------------------------------------------
814 #-----------------------------------------------------------------------------
815
815
816
816
817 class IPClusterLauncher(LocalProcessLauncher):
817 class IPClusterLauncher(LocalProcessLauncher):
818 """Launch the ipcluster program in an external process."""
818 """Launch the ipcluster program in an external process."""
819
819
820 ipcluster_cmd = List(ipcluster_cmd_argv, config=True)
820 ipcluster_cmd = List(ipcluster_cmd_argv, config=True)
821 # Command line arguments to pass to ipcluster.
821 # Command line arguments to pass to ipcluster.
822 ipcluster_args = List(
822 ipcluster_args = List(
823 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
823 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
824 ipcluster_subcommand = Str('start')
824 ipcluster_subcommand = Str('start')
825 ipcluster_n = Int(2)
825 ipcluster_n = Int(2)
826
826
827 def find_args(self):
827 def find_args(self):
828 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
828 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
829 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
829 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
830
830
831 def start(self):
831 def start(self):
832 log.msg("Starting ipcluster: %r" % self.args)
832 log.msg("Starting ipcluster: %r" % self.args)
833 return super(IPClusterLauncher, self).start()
833 return super(IPClusterLauncher, self).start()
834
834
@@ -1,186 +1,186 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 """Tests for pendingdeferred.py"""
4 """Tests for pendingdeferred.py"""
5
5
6 __docformat__ = "restructuredtext en"
6 __docformat__ = "restructuredtext en"
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18
18
19 # Tell nose to skip this module
19 # Tell nose to skip this module
20 __test__ = {}
20 __test__ = {}
21
21
22 from twisted.internet import defer
22 from twisted.internet import defer
23 from twisted.python import failure
23 from twisted.python import failure
24
24
25 from IPython.testing.util import DeferredTestCase
25 from IPython.testing.util import DeferredTestCase
26 import IPython.kernel.pendingdeferred as pd
26 import IPython.kernel.pendingdeferred as pd
27 from IPython.kernel import error
27 from IPython.kernel import error
28 from IPython.kernel.util import printer
28 from IPython.kernel.util import printer
29
29
30
30
31 class Foo(object):
31 class Foo(object):
32
32
33 def bar(self, bahz):
33 def bar(self, bahz):
34 return defer.succeed('blahblah: %s' % bahz)
34 return defer.succeed('blahblah: %s' % bahz)
35
35
36 class TwoPhaseFoo(pd.PendingDeferredManager):
36 class TwoPhaseFoo(pd.PendingDeferredManager):
37
37
38 def __init__(self, foo):
38 def __init__(self, foo):
39 self.foo = foo
39 self.foo = foo
40 pd.PendingDeferredManager.__init__(self)
40 pd.PendingDeferredManager.__init__(self)
41
41
42 @pd.two_phase
42 @pd.two_phase
43 def bar(self, bahz):
43 def bar(self, bahz):
44 return self.foo.bar(bahz)
44 return self.foo.bar(bahz)
45
45
46 class PendingDeferredManagerTest(DeferredTestCase):
46 class PendingDeferredManagerTest(DeferredTestCase):
47
47
48 def setUp(self):
48 def setUp(self):
49 self.pdm = pd.PendingDeferredManager()
49 self.pdm = pd.PendingDeferredManager()
50
50
51 def tearDown(self):
51 def tearDown(self):
52 pass
52 pass
53
53
54 def testBasic(self):
54 def testBasic(self):
55 dDict = {}
55 dDict = {}
56 # Create 10 deferreds and save them
56 # Create 10 deferreds and save them
57 for i in range(10):
57 for i in range(10):
58 d = defer.Deferred()
58 d = defer.Deferred()
59 did = self.pdm.save_pending_deferred(d)
59 did = self.pdm.save_pending_deferred(d)
60 dDict[did] = d
60 dDict[did] = d
61 # Make sure they are begin saved
61 # Make sure they are begin saved
62 for k in dDict.keys():
62 for k in dDict.iterkeys():
63 self.assert_(self.pdm.quick_has_id(k))
63 self.assert_(self.pdm.quick_has_id(k))
64 # Get the pending deferred (block=True), then callback with 'foo' and compare
64 # Get the pending deferred (block=True), then callback with 'foo' and compare
65 for did in dDict.keys()[0:5]:
65 for did in dDict.keys()[0:5]:
66 d = self.pdm.get_pending_deferred(did,block=True)
66 d = self.pdm.get_pending_deferred(did,block=True)
67 dDict[did].callback('foo')
67 dDict[did].callback('foo')
68 d.addCallback(lambda r: self.assert_(r=='foo'))
68 d.addCallback(lambda r: self.assert_(r=='foo'))
69 # Get the pending deferreds with (block=False) and make sure ResultNotCompleted is raised
69 # Get the pending deferreds with (block=False) and make sure ResultNotCompleted is raised
70 for did in dDict.keys()[5:10]:
70 for did in dDict.keys()[5:10]:
71 d = self.pdm.get_pending_deferred(did,block=False)
71 d = self.pdm.get_pending_deferred(did,block=False)
72 d.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
72 d.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
73 # Now callback the last 5, get them and compare.
73 # Now callback the last 5, get them and compare.
74 for did in dDict.keys()[5:10]:
74 for did in dDict.keys()[5:10]:
75 dDict[did].callback('foo')
75 dDict[did].callback('foo')
76 d = self.pdm.get_pending_deferred(did,block=False)
76 d = self.pdm.get_pending_deferred(did,block=False)
77 d.addCallback(lambda r: self.assert_(r=='foo'))
77 d.addCallback(lambda r: self.assert_(r=='foo'))
78
78
79 def test_save_then_delete(self):
79 def test_save_then_delete(self):
80 d = defer.Deferred()
80 d = defer.Deferred()
81 did = self.pdm.save_pending_deferred(d)
81 did = self.pdm.save_pending_deferred(d)
82 self.assert_(self.pdm.quick_has_id(did))
82 self.assert_(self.pdm.quick_has_id(did))
83 self.pdm.delete_pending_deferred(did)
83 self.pdm.delete_pending_deferred(did)
84 self.assert_(not self.pdm.quick_has_id(did))
84 self.assert_(not self.pdm.quick_has_id(did))
85
85
86 def test_save_get_delete(self):
86 def test_save_get_delete(self):
87 d = defer.Deferred()
87 d = defer.Deferred()
88 did = self.pdm.save_pending_deferred(d)
88 did = self.pdm.save_pending_deferred(d)
89 d2 = self.pdm.get_pending_deferred(did,True)
89 d2 = self.pdm.get_pending_deferred(did,True)
90 d2.addErrback(lambda f: self.assertRaises(error.AbortedPendingDeferredError, f.raiseException))
90 d2.addErrback(lambda f: self.assertRaises(error.AbortedPendingDeferredError, f.raiseException))
91 self.pdm.delete_pending_deferred(did)
91 self.pdm.delete_pending_deferred(did)
92 return d2
92 return d2
93
93
94 def test_double_get(self):
94 def test_double_get(self):
95 d = defer.Deferred()
95 d = defer.Deferred()
96 did = self.pdm.save_pending_deferred(d)
96 did = self.pdm.save_pending_deferred(d)
97 d2 = self.pdm.get_pending_deferred(did,True)
97 d2 = self.pdm.get_pending_deferred(did,True)
98 d3 = self.pdm.get_pending_deferred(did,True)
98 d3 = self.pdm.get_pending_deferred(did,True)
99 d3.addErrback(lambda f: self.assertRaises(error.InvalidDeferredID, f.raiseException))
99 d3.addErrback(lambda f: self.assertRaises(error.InvalidDeferredID, f.raiseException))
100
100
101 def test_get_after_callback(self):
101 def test_get_after_callback(self):
102 d = defer.Deferred()
102 d = defer.Deferred()
103 did = self.pdm.save_pending_deferred(d)
103 did = self.pdm.save_pending_deferred(d)
104 d.callback('foo')
104 d.callback('foo')
105 d2 = self.pdm.get_pending_deferred(did,True)
105 d2 = self.pdm.get_pending_deferred(did,True)
106 d2.addCallback(lambda r: self.assertEquals(r,'foo'))
106 d2.addCallback(lambda r: self.assertEquals(r,'foo'))
107 self.assert_(not self.pdm.quick_has_id(did))
107 self.assert_(not self.pdm.quick_has_id(did))
108
108
109 def test_get_before_callback(self):
109 def test_get_before_callback(self):
110 d = defer.Deferred()
110 d = defer.Deferred()
111 did = self.pdm.save_pending_deferred(d)
111 did = self.pdm.save_pending_deferred(d)
112 d2 = self.pdm.get_pending_deferred(did,True)
112 d2 = self.pdm.get_pending_deferred(did,True)
113 d.callback('foo')
113 d.callback('foo')
114 d2.addCallback(lambda r: self.assertEquals(r,'foo'))
114 d2.addCallback(lambda r: self.assertEquals(r,'foo'))
115 self.assert_(not self.pdm.quick_has_id(did))
115 self.assert_(not self.pdm.quick_has_id(did))
116 d = defer.Deferred()
116 d = defer.Deferred()
117 did = self.pdm.save_pending_deferred(d)
117 did = self.pdm.save_pending_deferred(d)
118 d2 = self.pdm.get_pending_deferred(did,True)
118 d2 = self.pdm.get_pending_deferred(did,True)
119 d2.addCallback(lambda r: self.assertEquals(r,'foo'))
119 d2.addCallback(lambda r: self.assertEquals(r,'foo'))
120 d.callback('foo')
120 d.callback('foo')
121 self.assert_(not self.pdm.quick_has_id(did))
121 self.assert_(not self.pdm.quick_has_id(did))
122
122
123 def test_get_after_errback(self):
123 def test_get_after_errback(self):
124 class MyError(Exception):
124 class MyError(Exception):
125 pass
125 pass
126 d = defer.Deferred()
126 d = defer.Deferred()
127 did = self.pdm.save_pending_deferred(d)
127 did = self.pdm.save_pending_deferred(d)
128 d.errback(failure.Failure(MyError('foo')))
128 d.errback(failure.Failure(MyError('foo')))
129 d2 = self.pdm.get_pending_deferred(did,True)
129 d2 = self.pdm.get_pending_deferred(did,True)
130 d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
130 d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
131 self.assert_(not self.pdm.quick_has_id(did))
131 self.assert_(not self.pdm.quick_has_id(did))
132
132
133 def test_get_before_errback(self):
133 def test_get_before_errback(self):
134 class MyError(Exception):
134 class MyError(Exception):
135 pass
135 pass
136 d = defer.Deferred()
136 d = defer.Deferred()
137 did = self.pdm.save_pending_deferred(d)
137 did = self.pdm.save_pending_deferred(d)
138 d2 = self.pdm.get_pending_deferred(did,True)
138 d2 = self.pdm.get_pending_deferred(did,True)
139 d.errback(failure.Failure(MyError('foo')))
139 d.errback(failure.Failure(MyError('foo')))
140 d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
140 d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
141 self.assert_(not self.pdm.quick_has_id(did))
141 self.assert_(not self.pdm.quick_has_id(did))
142 d = defer.Deferred()
142 d = defer.Deferred()
143 did = self.pdm.save_pending_deferred(d)
143 did = self.pdm.save_pending_deferred(d)
144 d2 = self.pdm.get_pending_deferred(did,True)
144 d2 = self.pdm.get_pending_deferred(did,True)
145 d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
145 d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
146 d.errback(failure.Failure(MyError('foo')))
146 d.errback(failure.Failure(MyError('foo')))
147 self.assert_(not self.pdm.quick_has_id(did))
147 self.assert_(not self.pdm.quick_has_id(did))
148
148
149 def test_noresult_noblock(self):
149 def test_noresult_noblock(self):
150 d = defer.Deferred()
150 d = defer.Deferred()
151 did = self.pdm.save_pending_deferred(d)
151 did = self.pdm.save_pending_deferred(d)
152 d2 = self.pdm.get_pending_deferred(did,False)
152 d2 = self.pdm.get_pending_deferred(did,False)
153 d2.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
153 d2.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
154
154
155 def test_with_callbacks(self):
155 def test_with_callbacks(self):
156 d = defer.Deferred()
156 d = defer.Deferred()
157 d.addCallback(lambda r: r+' foo')
157 d.addCallback(lambda r: r+' foo')
158 d.addCallback(lambda r: r+' bar')
158 d.addCallback(lambda r: r+' bar')
159 did = self.pdm.save_pending_deferred(d)
159 did = self.pdm.save_pending_deferred(d)
160 d2 = self.pdm.get_pending_deferred(did,True)
160 d2 = self.pdm.get_pending_deferred(did,True)
161 d.callback('bam')
161 d.callback('bam')
162 d2.addCallback(lambda r: self.assertEquals(r,'bam foo bar'))
162 d2.addCallback(lambda r: self.assertEquals(r,'bam foo bar'))
163
163
164 def test_with_errbacks(self):
164 def test_with_errbacks(self):
165 class MyError(Exception):
165 class MyError(Exception):
166 pass
166 pass
167 d = defer.Deferred()
167 d = defer.Deferred()
168 d.addCallback(lambda r: 'foo')
168 d.addCallback(lambda r: 'foo')
169 d.addErrback(lambda f: 'caught error')
169 d.addErrback(lambda f: 'caught error')
170 did = self.pdm.save_pending_deferred(d)
170 did = self.pdm.save_pending_deferred(d)
171 d2 = self.pdm.get_pending_deferred(did,True)
171 d2 = self.pdm.get_pending_deferred(did,True)
172 d.errback(failure.Failure(MyError('bam')))
172 d.errback(failure.Failure(MyError('bam')))
173 d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
173 d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
174
174
175 def test_nested_deferreds(self):
175 def test_nested_deferreds(self):
176 d = defer.Deferred()
176 d = defer.Deferred()
177 d2 = defer.Deferred()
177 d2 = defer.Deferred()
178 d.addCallback(lambda r: d2)
178 d.addCallback(lambda r: d2)
179 did = self.pdm.save_pending_deferred(d)
179 did = self.pdm.save_pending_deferred(d)
180 d.callback('foo')
180 d.callback('foo')
181 d3 = self.pdm.get_pending_deferred(did,False)
181 d3 = self.pdm.get_pending_deferred(did,False)
182 d3.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
182 d3.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
183 d2.callback('bar')
183 d2.callback('bar')
184 d3 = self.pdm.get_pending_deferred(did,False)
184 d3 = self.pdm.get_pending_deferred(did,False)
185 d3.addCallback(lambda r: self.assertEquals(r,'bar'))
185 d3.addCallback(lambda r: self.assertEquals(r,'bar'))
186
186
@@ -1,316 +1,316 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Job and task components for writing .xml files that the Windows HPC Server
4 Job and task components for writing .xml files that the Windows HPC Server
5 2008 can use to start jobs.
5 2008 can use to start jobs.
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2009 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from __future__ import with_statement
19 from __future__ import with_statement
20
20
21 import os
21 import os
22 import re
22 import re
23 import uuid
23 import uuid
24
24
25 from xml.etree import ElementTree as ET
25 from xml.etree import ElementTree as ET
26
26
27 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
28 from IPython.utils.traitlets import (
28 from IPython.utils.traitlets import (
29 Str, Int, List, Instance,
29 Str, Int, List, Instance,
30 Enum, Bool, CStr
30 Enum, Bool, CStr
31 )
31 )
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Job and Task classes
34 # Job and Task classes
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37
37
38 def as_str(value):
38 def as_str(value):
39 if isinstance(value, str):
39 if isinstance(value, str):
40 return value
40 return value
41 elif isinstance(value, bool):
41 elif isinstance(value, bool):
42 if value:
42 if value:
43 return 'true'
43 return 'true'
44 else:
44 else:
45 return 'false'
45 return 'false'
46 elif isinstance(value, (int, float)):
46 elif isinstance(value, (int, float)):
47 return repr(value)
47 return repr(value)
48 else:
48 else:
49 return value
49 return value
50
50
51
51
52 def indent(elem, level=0):
52 def indent(elem, level=0):
53 i = "\n" + level*" "
53 i = "\n" + level*" "
54 if len(elem):
54 if len(elem):
55 if not elem.text or not elem.text.strip():
55 if not elem.text or not elem.text.strip():
56 elem.text = i + " "
56 elem.text = i + " "
57 if not elem.tail or not elem.tail.strip():
57 if not elem.tail or not elem.tail.strip():
58 elem.tail = i
58 elem.tail = i
59 for elem in elem:
59 for elem in elem:
60 indent(elem, level+1)
60 indent(elem, level+1)
61 if not elem.tail or not elem.tail.strip():
61 if not elem.tail or not elem.tail.strip():
62 elem.tail = i
62 elem.tail = i
63 else:
63 else:
64 if level and (not elem.tail or not elem.tail.strip()):
64 if level and (not elem.tail or not elem.tail.strip()):
65 elem.tail = i
65 elem.tail = i
66
66
67
67
68 def find_username():
68 def find_username():
69 domain = os.environ.get('USERDOMAIN')
69 domain = os.environ.get('USERDOMAIN')
70 username = os.environ.get('USERNAME','')
70 username = os.environ.get('USERNAME','')
71 if domain is None:
71 if domain is None:
72 return username
72 return username
73 else:
73 else:
74 return '%s\\%s' % (domain, username)
74 return '%s\\%s' % (domain, username)
75
75
76
76
77 class WinHPCJob(Configurable):
77 class WinHPCJob(Configurable):
78
78
79 job_id = Str('')
79 job_id = Str('')
80 job_name = Str('MyJob', config=True)
80 job_name = Str('MyJob', config=True)
81 min_cores = Int(1, config=True)
81 min_cores = Int(1, config=True)
82 max_cores = Int(1, config=True)
82 max_cores = Int(1, config=True)
83 min_sockets = Int(1, config=True)
83 min_sockets = Int(1, config=True)
84 max_sockets = Int(1, config=True)
84 max_sockets = Int(1, config=True)
85 min_nodes = Int(1, config=True)
85 min_nodes = Int(1, config=True)
86 max_nodes = Int(1, config=True)
86 max_nodes = Int(1, config=True)
87 unit_type = Str("Core", config=True)
87 unit_type = Str("Core", config=True)
88 auto_calculate_min = Bool(True, config=True)
88 auto_calculate_min = Bool(True, config=True)
89 auto_calculate_max = Bool(True, config=True)
89 auto_calculate_max = Bool(True, config=True)
90 run_until_canceled = Bool(False, config=True)
90 run_until_canceled = Bool(False, config=True)
91 is_exclusive = Bool(False, config=True)
91 is_exclusive = Bool(False, config=True)
92 username = Str(find_username(), config=True)
92 username = Str(find_username(), config=True)
93 job_type = Str('Batch', config=True)
93 job_type = Str('Batch', config=True)
94 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
94 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
95 default_value='Highest', config=True)
95 default_value='Highest', config=True)
96 requested_nodes = Str('', config=True)
96 requested_nodes = Str('', config=True)
97 project = Str('IPython', config=True)
97 project = Str('IPython', config=True)
98 xmlns = Str('http://schemas.microsoft.com/HPCS2008/scheduler/')
98 xmlns = Str('http://schemas.microsoft.com/HPCS2008/scheduler/')
99 version = Str("2.000")
99 version = Str("2.000")
100 tasks = List([])
100 tasks = List([])
101
101
102 @property
102 @property
103 def owner(self):
103 def owner(self):
104 return self.username
104 return self.username
105
105
106 def _write_attr(self, root, attr, key):
106 def _write_attr(self, root, attr, key):
107 s = as_str(getattr(self, attr, ''))
107 s = as_str(getattr(self, attr, ''))
108 if s:
108 if s:
109 root.set(key, s)
109 root.set(key, s)
110
110
111 def as_element(self):
111 def as_element(self):
112 # We have to add _A_ type things to get the right order than
112 # We have to add _A_ type things to get the right order than
113 # the MSFT XML parser expects.
113 # the MSFT XML parser expects.
114 root = ET.Element('Job')
114 root = ET.Element('Job')
115 self._write_attr(root, 'version', '_A_Version')
115 self._write_attr(root, 'version', '_A_Version')
116 self._write_attr(root, 'job_name', '_B_Name')
116 self._write_attr(root, 'job_name', '_B_Name')
117 self._write_attr(root, 'unit_type', '_C_UnitType')
117 self._write_attr(root, 'unit_type', '_C_UnitType')
118 self._write_attr(root, 'min_cores', '_D_MinCores')
118 self._write_attr(root, 'min_cores', '_D_MinCores')
119 self._write_attr(root, 'max_cores', '_E_MaxCores')
119 self._write_attr(root, 'max_cores', '_E_MaxCores')
120 self._write_attr(root, 'min_sockets', '_F_MinSockets')
120 self._write_attr(root, 'min_sockets', '_F_MinSockets')
121 self._write_attr(root, 'max_sockets', '_G_MaxSockets')
121 self._write_attr(root, 'max_sockets', '_G_MaxSockets')
122 self._write_attr(root, 'min_nodes', '_H_MinNodes')
122 self._write_attr(root, 'min_nodes', '_H_MinNodes')
123 self._write_attr(root, 'max_nodes', '_I_MaxNodes')
123 self._write_attr(root, 'max_nodes', '_I_MaxNodes')
124 self._write_attr(root, 'run_until_canceled', '_J_RunUntilCanceled')
124 self._write_attr(root, 'run_until_canceled', '_J_RunUntilCanceled')
125 self._write_attr(root, 'is_exclusive', '_K_IsExclusive')
125 self._write_attr(root, 'is_exclusive', '_K_IsExclusive')
126 self._write_attr(root, 'username', '_L_UserName')
126 self._write_attr(root, 'username', '_L_UserName')
127 self._write_attr(root, 'job_type', '_M_JobType')
127 self._write_attr(root, 'job_type', '_M_JobType')
128 self._write_attr(root, 'priority', '_N_Priority')
128 self._write_attr(root, 'priority', '_N_Priority')
129 self._write_attr(root, 'requested_nodes', '_O_RequestedNodes')
129 self._write_attr(root, 'requested_nodes', '_O_RequestedNodes')
130 self._write_attr(root, 'auto_calculate_max', '_P_AutoCalculateMax')
130 self._write_attr(root, 'auto_calculate_max', '_P_AutoCalculateMax')
131 self._write_attr(root, 'auto_calculate_min', '_Q_AutoCalculateMin')
131 self._write_attr(root, 'auto_calculate_min', '_Q_AutoCalculateMin')
132 self._write_attr(root, 'project', '_R_Project')
132 self._write_attr(root, 'project', '_R_Project')
133 self._write_attr(root, 'owner', '_S_Owner')
133 self._write_attr(root, 'owner', '_S_Owner')
134 self._write_attr(root, 'xmlns', '_T_xmlns')
134 self._write_attr(root, 'xmlns', '_T_xmlns')
135 dependencies = ET.SubElement(root, "Dependencies")
135 dependencies = ET.SubElement(root, "Dependencies")
136 etasks = ET.SubElement(root, "Tasks")
136 etasks = ET.SubElement(root, "Tasks")
137 for t in self.tasks:
137 for t in self.tasks:
138 etasks.append(t.as_element())
138 etasks.append(t.as_element())
139 return root
139 return root
140
140
141 def tostring(self):
141 def tostring(self):
142 """Return the string representation of the job description XML."""
142 """Return the string representation of the job description XML."""
143 root = self.as_element()
143 root = self.as_element()
144 indent(root)
144 indent(root)
145 txt = ET.tostring(root, encoding="utf-8")
145 txt = ET.tostring(root, encoding="utf-8")
146 # Now remove the tokens used to order the attributes.
146 # Now remove the tokens used to order the attributes.
147 txt = re.sub(r'_[A-Z]_','',txt)
147 txt = re.sub(r'_[A-Z]_','',txt)
148 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
148 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
149 return txt
149 return txt
150
150
151 def write(self, filename):
151 def write(self, filename):
152 """Write the XML job description to a file."""
152 """Write the XML job description to a file."""
153 txt = self.tostring()
153 txt = self.tostring()
154 with open(filename, 'w') as f:
154 with open(filename, 'w') as f:
155 f.write(txt)
155 f.write(txt)
156
156
157 def add_task(self, task):
157 def add_task(self, task):
158 """Add a task to the job.
158 """Add a task to the job.
159
159
160 Parameters
160 Parameters
161 ----------
161 ----------
162 task : :class:`WinHPCTask`
162 task : :class:`WinHPCTask`
163 The task object to add.
163 The task object to add.
164 """
164 """
165 self.tasks.append(task)
165 self.tasks.append(task)
166
166
167
167
168 class WinHPCTask(Configurable):
168 class WinHPCTask(Configurable):
169
169
170 task_id = Str('')
170 task_id = Str('')
171 task_name = Str('')
171 task_name = Str('')
172 version = Str("2.000")
172 version = Str("2.000")
173 min_cores = Int(1, config=True)
173 min_cores = Int(1, config=True)
174 max_cores = Int(1, config=True)
174 max_cores = Int(1, config=True)
175 min_sockets = Int(1, config=True)
175 min_sockets = Int(1, config=True)
176 max_sockets = Int(1, config=True)
176 max_sockets = Int(1, config=True)
177 min_nodes = Int(1, config=True)
177 min_nodes = Int(1, config=True)
178 max_nodes = Int(1, config=True)
178 max_nodes = Int(1, config=True)
179 unit_type = Str("Core", config=True)
179 unit_type = Str("Core", config=True)
180 command_line = CStr('', config=True)
180 command_line = CStr('', config=True)
181 work_directory = CStr('', config=True)
181 work_directory = CStr('', config=True)
182 is_rerunnaable = Bool(True, config=True)
182 is_rerunnaable = Bool(True, config=True)
183 std_out_file_path = CStr('', config=True)
183 std_out_file_path = CStr('', config=True)
184 std_err_file_path = CStr('', config=True)
184 std_err_file_path = CStr('', config=True)
185 is_parametric = Bool(False, config=True)
185 is_parametric = Bool(False, config=True)
186 environment_variables = Instance(dict, args=(), config=True)
186 environment_variables = Instance(dict, args=(), config=True)
187
187
188 def _write_attr(self, root, attr, key):
188 def _write_attr(self, root, attr, key):
189 s = as_str(getattr(self, attr, ''))
189 s = as_str(getattr(self, attr, ''))
190 if s:
190 if s:
191 root.set(key, s)
191 root.set(key, s)
192
192
193 def as_element(self):
193 def as_element(self):
194 root = ET.Element('Task')
194 root = ET.Element('Task')
195 self._write_attr(root, 'version', '_A_Version')
195 self._write_attr(root, 'version', '_A_Version')
196 self._write_attr(root, 'task_name', '_B_Name')
196 self._write_attr(root, 'task_name', '_B_Name')
197 self._write_attr(root, 'min_cores', '_C_MinCores')
197 self._write_attr(root, 'min_cores', '_C_MinCores')
198 self._write_attr(root, 'max_cores', '_D_MaxCores')
198 self._write_attr(root, 'max_cores', '_D_MaxCores')
199 self._write_attr(root, 'min_sockets', '_E_MinSockets')
199 self._write_attr(root, 'min_sockets', '_E_MinSockets')
200 self._write_attr(root, 'max_sockets', '_F_MaxSockets')
200 self._write_attr(root, 'max_sockets', '_F_MaxSockets')
201 self._write_attr(root, 'min_nodes', '_G_MinNodes')
201 self._write_attr(root, 'min_nodes', '_G_MinNodes')
202 self._write_attr(root, 'max_nodes', '_H_MaxNodes')
202 self._write_attr(root, 'max_nodes', '_H_MaxNodes')
203 self._write_attr(root, 'command_line', '_I_CommandLine')
203 self._write_attr(root, 'command_line', '_I_CommandLine')
204 self._write_attr(root, 'work_directory', '_J_WorkDirectory')
204 self._write_attr(root, 'work_directory', '_J_WorkDirectory')
205 self._write_attr(root, 'is_rerunnaable', '_K_IsRerunnable')
205 self._write_attr(root, 'is_rerunnaable', '_K_IsRerunnable')
206 self._write_attr(root, 'std_out_file_path', '_L_StdOutFilePath')
206 self._write_attr(root, 'std_out_file_path', '_L_StdOutFilePath')
207 self._write_attr(root, 'std_err_file_path', '_M_StdErrFilePath')
207 self._write_attr(root, 'std_err_file_path', '_M_StdErrFilePath')
208 self._write_attr(root, 'is_parametric', '_N_IsParametric')
208 self._write_attr(root, 'is_parametric', '_N_IsParametric')
209 self._write_attr(root, 'unit_type', '_O_UnitType')
209 self._write_attr(root, 'unit_type', '_O_UnitType')
210 root.append(self.get_env_vars())
210 root.append(self.get_env_vars())
211 return root
211 return root
212
212
213 def get_env_vars(self):
213 def get_env_vars(self):
214 env_vars = ET.Element('EnvironmentVariables')
214 env_vars = ET.Element('EnvironmentVariables')
215 for k, v in self.environment_variables.items():
215 for k, v in self.environment_variables.iteritems():
216 variable = ET.SubElement(env_vars, "Variable")
216 variable = ET.SubElement(env_vars, "Variable")
217 name = ET.SubElement(variable, "Name")
217 name = ET.SubElement(variable, "Name")
218 name.text = k
218 name.text = k
219 value = ET.SubElement(variable, "Value")
219 value = ET.SubElement(variable, "Value")
220 value.text = v
220 value.text = v
221 return env_vars
221 return env_vars
222
222
223
223
224
224
225 # By declaring these, we can configure the controller and engine separately!
225 # By declaring these, we can configure the controller and engine separately!
226
226
227 class IPControllerJob(WinHPCJob):
227 class IPControllerJob(WinHPCJob):
228 job_name = Str('IPController', config=False)
228 job_name = Str('IPController', config=False)
229 is_exclusive = Bool(False, config=True)
229 is_exclusive = Bool(False, config=True)
230 username = Str(find_username(), config=True)
230 username = Str(find_username(), config=True)
231 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
231 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
232 default_value='Highest', config=True)
232 default_value='Highest', config=True)
233 requested_nodes = Str('', config=True)
233 requested_nodes = Str('', config=True)
234 project = Str('IPython', config=True)
234 project = Str('IPython', config=True)
235
235
236
236
237 class IPEngineSetJob(WinHPCJob):
237 class IPEngineSetJob(WinHPCJob):
238 job_name = Str('IPEngineSet', config=False)
238 job_name = Str('IPEngineSet', config=False)
239 is_exclusive = Bool(False, config=True)
239 is_exclusive = Bool(False, config=True)
240 username = Str(find_username(), config=True)
240 username = Str(find_username(), config=True)
241 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
241 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
242 default_value='Highest', config=True)
242 default_value='Highest', config=True)
243 requested_nodes = Str('', config=True)
243 requested_nodes = Str('', config=True)
244 project = Str('IPython', config=True)
244 project = Str('IPython', config=True)
245
245
246
246
247 class IPControllerTask(WinHPCTask):
247 class IPControllerTask(WinHPCTask):
248
248
249 task_name = Str('IPController', config=True)
249 task_name = Str('IPController', config=True)
250 controller_cmd = List(['ipcontroller.exe'], config=True)
250 controller_cmd = List(['ipcontroller.exe'], config=True)
251 controller_args = List(['--log-to-file', '--log-level', '40'], config=True)
251 controller_args = List(['--log-to-file', '--log-level', '40'], config=True)
252 # I don't want these to be configurable
252 # I don't want these to be configurable
253 std_out_file_path = CStr('', config=False)
253 std_out_file_path = CStr('', config=False)
254 std_err_file_path = CStr('', config=False)
254 std_err_file_path = CStr('', config=False)
255 min_cores = Int(1, config=False)
255 min_cores = Int(1, config=False)
256 max_cores = Int(1, config=False)
256 max_cores = Int(1, config=False)
257 min_sockets = Int(1, config=False)
257 min_sockets = Int(1, config=False)
258 max_sockets = Int(1, config=False)
258 max_sockets = Int(1, config=False)
259 min_nodes = Int(1, config=False)
259 min_nodes = Int(1, config=False)
260 max_nodes = Int(1, config=False)
260 max_nodes = Int(1, config=False)
261 unit_type = Str("Core", config=False)
261 unit_type = Str("Core", config=False)
262 work_directory = CStr('', config=False)
262 work_directory = CStr('', config=False)
263
263
264 def __init__(self, config=None):
264 def __init__(self, config=None):
265 super(IPControllerTask, self).__init__(config=config)
265 super(IPControllerTask, self).__init__(config=config)
266 the_uuid = uuid.uuid1()
266 the_uuid = uuid.uuid1()
267 self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid)
267 self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid)
268 self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid)
268 self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid)
269
269
270 @property
270 @property
271 def command_line(self):
271 def command_line(self):
272 return ' '.join(self.controller_cmd + self.controller_args)
272 return ' '.join(self.controller_cmd + self.controller_args)
273
273
274
274
275 class IPEngineTask(WinHPCTask):
275 class IPEngineTask(WinHPCTask):
276
276
277 task_name = Str('IPEngine', config=True)
277 task_name = Str('IPEngine', config=True)
278 engine_cmd = List(['ipengine.exe'], config=True)
278 engine_cmd = List(['ipengine.exe'], config=True)
279 engine_args = List(['--log-to-file', '--log-level', '40'], config=True)
279 engine_args = List(['--log-to-file', '--log-level', '40'], config=True)
280 # I don't want these to be configurable
280 # I don't want these to be configurable
281 std_out_file_path = CStr('', config=False)
281 std_out_file_path = CStr('', config=False)
282 std_err_file_path = CStr('', config=False)
282 std_err_file_path = CStr('', config=False)
283 min_cores = Int(1, config=False)
283 min_cores = Int(1, config=False)
284 max_cores = Int(1, config=False)
284 max_cores = Int(1, config=False)
285 min_sockets = Int(1, config=False)
285 min_sockets = Int(1, config=False)
286 max_sockets = Int(1, config=False)
286 max_sockets = Int(1, config=False)
287 min_nodes = Int(1, config=False)
287 min_nodes = Int(1, config=False)
288 max_nodes = Int(1, config=False)
288 max_nodes = Int(1, config=False)
289 unit_type = Str("Core", config=False)
289 unit_type = Str("Core", config=False)
290 work_directory = CStr('', config=False)
290 work_directory = CStr('', config=False)
291
291
292 def __init__(self, config=None):
292 def __init__(self, config=None):
293 super(IPEngineTask,self).__init__(config=config)
293 super(IPEngineTask,self).__init__(config=config)
294 the_uuid = uuid.uuid1()
294 the_uuid = uuid.uuid1()
295 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
295 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
296 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
296 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
297
297
298 @property
298 @property
299 def command_line(self):
299 def command_line(self):
300 return ' '.join(self.engine_cmd + self.engine_args)
300 return ' '.join(self.engine_cmd + self.engine_args)
301
301
302
302
303 # j = WinHPCJob(None)
303 # j = WinHPCJob(None)
304 # j.job_name = 'IPCluster'
304 # j.job_name = 'IPCluster'
305 # j.username = 'GNET\\bgranger'
305 # j.username = 'GNET\\bgranger'
306 # j.requested_nodes = 'GREEN'
306 # j.requested_nodes = 'GREEN'
307 #
307 #
308 # t = WinHPCTask(None)
308 # t = WinHPCTask(None)
309 # t.task_name = 'Controller'
309 # t.task_name = 'Controller'
310 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
310 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
311 # t.work_directory = r"\\blue\domainusers$\bgranger\.ipython\cluster_default"
311 # t.work_directory = r"\\blue\domainusers$\bgranger\.ipython\cluster_default"
312 # t.std_out_file_path = 'controller-out.txt'
312 # t.std_out_file_path = 'controller-out.txt'
313 # t.std_err_file_path = 'controller-err.txt'
313 # t.std_err_file_path = 'controller-err.txt'
314 # t.environment_variables['PYTHONPATH'] = r"\\blue\domainusers$\bgranger\Python\Python25\Lib\site-packages"
314 # t.environment_variables['PYTHONPATH'] = r"\\blue\domainusers$\bgranger\Python\Python25\Lib\site-packages"
315 # j.add_task(t)
315 # j.add_task(t)
316
316
General Comments 0
You need to be logged in to leave comments. Login now