##// END OF EJS Templates
Modify tests to expect unicode. Now all tests pass again.
Thomas Kluyver -
Show More
@@ -1,383 +1,384 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # coding: utf-8
2 # coding: utf-8
3 """A simple configuration system.
3 """A simple configuration system.
4
4
5 Authors
5 Authors
6 -------
6 -------
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2009 The IPython Development Team
12 # Copyright (C) 2008-2009 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import __builtin__
22 import __builtin__
23 import os
23 import os
24 import sys
24 import sys
25
25
26 from IPython.external import argparse
26 from IPython.external import argparse
27 from IPython.utils.path import filefind
27 from IPython.utils.path import filefind
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Exceptions
30 # Exceptions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33
33
34 class ConfigError(Exception):
34 class ConfigError(Exception):
35 pass
35 pass
36
36
37
37
38 class ConfigLoaderError(ConfigError):
38 class ConfigLoaderError(ConfigError):
39 pass
39 pass
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Argparse fix
42 # Argparse fix
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45 # Unfortunately argparse by default prints help messages to stderr instead of
45 # Unfortunately argparse by default prints help messages to stderr instead of
46 # 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
47 # 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
48 # 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
49 # stdout and use our class instead.
49 # stdout and use our class instead.
50
50
51 class ArgumentParser(argparse.ArgumentParser):
51 class ArgumentParser(argparse.ArgumentParser):
52 """Simple argparse subclass that prints help to stdout by default."""
52 """Simple argparse subclass that prints help to stdout by default."""
53
53
54 def print_help(self, file=None):
54 def print_help(self, file=None):
55 if file is None:
55 if file is None:
56 file = sys.stdout
56 file = sys.stdout
57 return super(ArgumentParser, self).print_help(file)
57 return super(ArgumentParser, self).print_help(file)
58
58
59 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
59 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Config class for holding config information
62 # Config class for holding config information
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65
65
66 class Config(dict):
66 class Config(dict):
67 """An attribute based dict that can do smart merges."""
67 """An attribute based dict that can do smart merges."""
68
68
69 def __init__(self, *args, **kwds):
69 def __init__(self, *args, **kwds):
70 dict.__init__(self, *args, **kwds)
70 dict.__init__(self, *args, **kwds)
71 # 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
72 # because we are also overriding __setattr__.
72 # because we are also overriding __setattr__.
73 dict.__setattr__(self, '__dict__', self)
73 dict.__setattr__(self, '__dict__', self)
74
74
75 def _merge(self, other):
75 def _merge(self, other):
76 to_update = {}
76 to_update = {}
77 for k, v in other.iteritems():
77 for k, v in other.iteritems():
78 if not self.has_key(k):
78 if not self.has_key(k):
79 to_update[k] = v
79 to_update[k] = v
80 else: # I have this key
80 else: # I have this key
81 if isinstance(v, Config):
81 if isinstance(v, Config):
82 # Recursively merge common sub Configs
82 # Recursively merge common sub Configs
83 self[k]._merge(v)
83 self[k]._merge(v)
84 else:
84 else:
85 # Plain updates for non-Configs
85 # Plain updates for non-Configs
86 to_update[k] = v
86 to_update[k] = v
87
87
88 self.update(to_update)
88 self.update(to_update)
89
89
90 def _is_section_key(self, key):
90 def _is_section_key(self, key):
91 if key[0].upper()==key[0] and not key.startswith('_'):
91 if key[0].upper()==key[0] and not key.startswith('_'):
92 return True
92 return True
93 else:
93 else:
94 return False
94 return False
95
95
96 def __contains__(self, key):
96 def __contains__(self, key):
97 if self._is_section_key(key):
97 if self._is_section_key(key):
98 return True
98 return True
99 else:
99 else:
100 return super(Config, self).__contains__(key)
100 return super(Config, self).__contains__(key)
101 # .has_key is deprecated for dictionaries.
101 # .has_key is deprecated for dictionaries.
102 has_key = __contains__
102 has_key = __contains__
103
103
104 def _has_section(self, key):
104 def _has_section(self, key):
105 if self._is_section_key(key):
105 if self._is_section_key(key):
106 if super(Config, self).__contains__(key):
106 if super(Config, self).__contains__(key):
107 return True
107 return True
108 return False
108 return False
109
109
110 def copy(self):
110 def copy(self):
111 return type(self)(dict.copy(self))
111 return type(self)(dict.copy(self))
112
112
113 def __copy__(self):
113 def __copy__(self):
114 return self.copy()
114 return self.copy()
115
115
116 def __deepcopy__(self, memo):
116 def __deepcopy__(self, memo):
117 import copy
117 import copy
118 return type(self)(copy.deepcopy(self.items()))
118 return type(self)(copy.deepcopy(self.items()))
119
119
120 def __getitem__(self, key):
120 def __getitem__(self, key):
121 # 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
122 # the lookup of names in __builtin__ to itself. This means
122 # the lookup of names in __builtin__ to itself. This means
123 # that you can't have section or attribute names that are
123 # that you can't have section or attribute names that are
124 # builtins.
124 # builtins.
125 try:
125 try:
126 return getattr(__builtin__, key)
126 return getattr(__builtin__, key)
127 except AttributeError:
127 except AttributeError:
128 pass
128 pass
129 if self._is_section_key(key):
129 if self._is_section_key(key):
130 try:
130 try:
131 return dict.__getitem__(self, key)
131 return dict.__getitem__(self, key)
132 except KeyError:
132 except KeyError:
133 c = Config()
133 c = Config()
134 dict.__setitem__(self, key, c)
134 dict.__setitem__(self, key, c)
135 return c
135 return c
136 else:
136 else:
137 return dict.__getitem__(self, key)
137 return dict.__getitem__(self, key)
138
138
139 def __setitem__(self, key, value):
139 def __setitem__(self, key, value):
140 # Don't allow names in __builtin__ to be modified.
140 # Don't allow names in __builtin__ to be modified.
141 if hasattr(__builtin__, key):
141 if hasattr(__builtin__, key):
142 raise ConfigError('Config variable names cannot have the same name '
142 raise ConfigError('Config variable names cannot have the same name '
143 'as a Python builtin: %s' % key)
143 'as a Python builtin: %s' % key)
144 if self._is_section_key(key):
144 if self._is_section_key(key):
145 if not isinstance(value, Config):
145 if not isinstance(value, Config):
146 raise ValueError('values whose keys begin with an uppercase '
146 raise ValueError('values whose keys begin with an uppercase '
147 'char must be Config instances: %r, %r' % (key, value))
147 'char must be Config instances: %r, %r' % (key, value))
148 else:
148 else:
149 dict.__setitem__(self, key, value)
149 dict.__setitem__(self, key, value)
150
150
151 def __getattr__(self, key):
151 def __getattr__(self, key):
152 try:
152 try:
153 return self.__getitem__(key)
153 return self.__getitem__(key)
154 except KeyError, e:
154 except KeyError, e:
155 raise AttributeError(e)
155 raise AttributeError(e)
156
156
157 def __setattr__(self, key, value):
157 def __setattr__(self, key, value):
158 try:
158 try:
159 self.__setitem__(key, value)
159 self.__setitem__(key, value)
160 except KeyError, e:
160 except KeyError, e:
161 raise AttributeError(e)
161 raise AttributeError(e)
162
162
163 def __delattr__(self, key):
163 def __delattr__(self, key):
164 try:
164 try:
165 dict.__delitem__(self, key)
165 dict.__delitem__(self, key)
166 except KeyError, e:
166 except KeyError, e:
167 raise AttributeError(e)
167 raise AttributeError(e)
168
168
169
169
170 #-----------------------------------------------------------------------------
170 #-----------------------------------------------------------------------------
171 # Config loading classes
171 # Config loading classes
172 #-----------------------------------------------------------------------------
172 #-----------------------------------------------------------------------------
173
173
174
174
175 class ConfigLoader(object):
175 class ConfigLoader(object):
176 """A object for loading configurations from just about anywhere.
176 """A object for loading configurations from just about anywhere.
177
177
178 The resulting configuration is packaged as a :class:`Struct`.
178 The resulting configuration is packaged as a :class:`Struct`.
179
179
180 Notes
180 Notes
181 -----
181 -----
182 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
183 (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`.
184 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
185 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
186 default values or merge multiple configs. These things need to be
186 default values or merge multiple configs. These things need to be
187 handled elsewhere.
187 handled elsewhere.
188 """
188 """
189
189
190 def __init__(self):
190 def __init__(self):
191 """A base class for config loaders.
191 """A base class for config loaders.
192
192
193 Examples
193 Examples
194 --------
194 --------
195
195
196 >>> cl = ConfigLoader()
196 >>> cl = ConfigLoader()
197 >>> config = cl.load_config()
197 >>> config = cl.load_config()
198 >>> config
198 >>> config
199 {}
199 {}
200 """
200 """
201 self.clear()
201 self.clear()
202
202
203 def clear(self):
203 def clear(self):
204 self.config = Config()
204 self.config = Config()
205
205
206 def load_config(self):
206 def load_config(self):
207 """Load a config from somewhere, return a :class:`Config` instance.
207 """Load a config from somewhere, return a :class:`Config` instance.
208
208
209 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.
210 However, in most cases, :meth:`ConfigLoader.clear` should be called
210 However, in most cases, :meth:`ConfigLoader.clear` should be called
211 to erase any previous state.
211 to erase any previous state.
212 """
212 """
213 self.clear()
213 self.clear()
214 return self.config
214 return self.config
215
215
216
216
217 class FileConfigLoader(ConfigLoader):
217 class FileConfigLoader(ConfigLoader):
218 """A base class for file based configurations.
218 """A base class for file based configurations.
219
219
220 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
221 here.
221 here.
222 """
222 """
223 pass
223 pass
224
224
225
225
226 class PyFileConfigLoader(FileConfigLoader):
226 class PyFileConfigLoader(FileConfigLoader):
227 """A config loader for pure python files.
227 """A config loader for pure python files.
228
228
229 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
230 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.
231 """
231 """
232
232
233 def __init__(self, filename, path=None):
233 def __init__(self, filename, path=None):
234 """Build a config loader for a filename and path.
234 """Build a config loader for a filename and path.
235
235
236 Parameters
236 Parameters
237 ----------
237 ----------
238 filename : str
238 filename : str
239 The file name of the config file.
239 The file name of the config file.
240 path : str, list, tuple
240 path : str, list, tuple
241 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
242 paths to try in order.
242 paths to try in order.
243 """
243 """
244 super(PyFileConfigLoader, self).__init__()
244 super(PyFileConfigLoader, self).__init__()
245 self.filename = filename
245 self.filename = filename
246 self.path = path
246 self.path = path
247 self.full_filename = ''
247 self.full_filename = ''
248 self.data = None
248 self.data = None
249
249
250 def load_config(self):
250 def load_config(self):
251 """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."""
252 self.clear()
252 self.clear()
253 self._find_file()
253 self._find_file()
254 self._read_file_as_dict()
254 self._read_file_as_dict()
255 self._convert_to_config()
255 self._convert_to_config()
256 return self.config
256 return self.config
257
257
258 def _find_file(self):
258 def _find_file(self):
259 """Try to find the file by searching the paths."""
259 """Try to find the file by searching the paths."""
260 self.full_filename = filefind(self.filename, self.path)
260 self.full_filename = filefind(self.filename, self.path)
261
261
262 def _read_file_as_dict(self):
262 def _read_file_as_dict(self):
263 """Load the config file into self.config, with recursive loading."""
263 """Load the config file into self.config, with recursive loading."""
264 # This closure is made available in the namespace that is used
264 # This closure is made available in the namespace that is used
265 # to exec the config file. This allows users to call
265 # to exec the config file. This allows users to call
266 # load_subconfig('myconfig.py') to load config files recursively.
266 # load_subconfig('myconfig.py') to load config files recursively.
267 # 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
268 # 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
269 # 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
270 # with the parents.
270 # with the parents.
271 def load_subconfig(fname):
271 def load_subconfig(fname):
272 loader = PyFileConfigLoader(fname, self.path)
272 loader = PyFileConfigLoader(fname, self.path)
273 try:
273 try:
274 sub_config = loader.load_config()
274 sub_config = loader.load_config()
275 except IOError:
275 except IOError:
276 # Pass silently if the sub config is not there. This happens
276 # Pass silently if the sub config is not there. This happens
277 # 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.
278 pass
278 pass
279 else:
279 else:
280 self.config._merge(sub_config)
280 self.config._merge(sub_config)
281
281
282 # 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
283 # files to get the config being loaded.
283 # files to get the config being loaded.
284 def get_config():
284 def get_config():
285 return self.config
285 return self.config
286
286
287 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
287 namespace = dict(load_subconfig=load_subconfig, get_config=get_config)
288 fs_encoding = sys.getfilesystemencoding() or 'ascii'
288 fs_encoding = sys.getfilesystemencoding() or 'ascii'
289 conf_filename = self.full_filename.encode(fs_encoding)
289 conf_filename = self.full_filename.encode(fs_encoding)
290 execfile(conf_filename, namespace)
290 execfile(conf_filename, namespace)
291
291
292 def _convert_to_config(self):
292 def _convert_to_config(self):
293 if self.data is None:
293 if self.data is None:
294 ConfigLoaderError('self.data does not exist')
294 ConfigLoaderError('self.data does not exist')
295
295
296
296
297 class CommandLineConfigLoader(ConfigLoader):
297 class CommandLineConfigLoader(ConfigLoader):
298 """A config loader for command line arguments.
298 """A config loader for command line arguments.
299
299
300 As we add more command line based loaders, the common logic should go
300 As we add more command line based loaders, the common logic should go
301 here.
301 here.
302 """
302 """
303
303
304
304
305 class ArgParseConfigLoader(CommandLineConfigLoader):
305 class ArgParseConfigLoader(CommandLineConfigLoader):
306
306
307 def __init__(self, argv=None, *parser_args, **parser_kw):
307 def __init__(self, argv=None, *parser_args, **parser_kw):
308 """Create a config loader for use with argparse.
308 """Create a config loader for use with argparse.
309
309
310 Parameters
310 Parameters
311 ----------
311 ----------
312
312
313 argv : optional, list
313 argv : optional, list
314 If given, used to read command-line arguments from, otherwise
314 If given, used to read command-line arguments from, otherwise
315 sys.argv[1:] is used.
315 sys.argv[1:] is used.
316
316
317 parser_args : tuple
317 parser_args : tuple
318 A tuple of positional arguments that will be passed to the
318 A tuple of positional arguments that will be passed to the
319 constructor of :class:`argparse.ArgumentParser`.
319 constructor of :class:`argparse.ArgumentParser`.
320
320
321 parser_kw : dict
321 parser_kw : dict
322 A tuple of keyword arguments that will be passed to the
322 A tuple of keyword arguments that will be passed to the
323 constructor of :class:`argparse.ArgumentParser`.
323 constructor of :class:`argparse.ArgumentParser`.
324 """
324 """
325 super(CommandLineConfigLoader, self).__init__()
325 super(CommandLineConfigLoader, self).__init__()
326 if argv == None:
326 if argv == None:
327 argv = sys.argv[1:]
327 argv = sys.argv[1:]
328 self.argv = argv
328 self.argv = argv
329 self.parser_args = parser_args
329 self.parser_args = parser_args
330 self.version = parser_kw.pop("version", None)
330 self.version = parser_kw.pop("version", None)
331 kwargs = dict(argument_default=argparse.SUPPRESS)
331 kwargs = dict(argument_default=argparse.SUPPRESS)
332 kwargs.update(parser_kw)
332 kwargs.update(parser_kw)
333 self.parser_kw = kwargs
333 self.parser_kw = kwargs
334
334
335 def load_config(self, args=None):
335 def load_config(self, args=None):
336 """Parse command line arguments and return as a Struct.
336 """Parse command line arguments and return as a Struct.
337
337
338 Parameters
338 Parameters
339 ----------
339 ----------
340
340
341 args : optional, list
341 args : optional, list
342 If given, a list with the structure of sys.argv[1:] to parse
342 If given, a list with the structure of sys.argv[1:] to parse
343 arguments from. If not given, the instance's self.argv attribute
343 arguments from. If not given, the instance's self.argv attribute
344 (given at construction time) is used."""
344 (given at construction time) is used."""
345 self.clear()
345 self.clear()
346 if args is None:
346 if args is None:
347 args = self.argv
347 args = self.argv
348 self._create_parser()
348 self._create_parser()
349 self._parse_args(args)
349 self._parse_args(args)
350 self._convert_to_config()
350 self._convert_to_config()
351 return self.config
351 return self.config
352
352
353 def get_extra_args(self):
353 def get_extra_args(self):
354 if hasattr(self, 'extra_args'):
354 if hasattr(self, 'extra_args'):
355 return self.extra_args
355 return self.extra_args
356 else:
356 else:
357 return []
357 return []
358
358
359 def _create_parser(self):
359 def _create_parser(self):
360 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
360 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
361 self._add_arguments()
361 self._add_arguments()
362
362
363 def _add_arguments(self):
363 def _add_arguments(self):
364 raise NotImplementedError("subclasses must implement _add_arguments")
364 raise NotImplementedError("subclasses must implement _add_arguments")
365
365
366 def _parse_args(self, args):
366 def _parse_args(self, args):
367 """self.parser->self.parsed_data"""
367 """self.parser->self.parsed_data"""
368 # decode sys.argv to support unicode command-line options
368 # decode sys.argv to support unicode command-line options
369 uargs = []
369 uargs = []
370 for a in args:
370 for a in args:
371 if isinstance(a, str):
371 if isinstance(a, str):
372 # don't decode if we already got unicode
372 # don't decode if we already got unicode
373 a = a.decode(sys.stdin.encoding)
373 a = a.decode(sys.stdin.encoding or
374 sys.getdefaultencoding())
374 uargs.append(a)
375 uargs.append(a)
375 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
376 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
376
377
377 def _convert_to_config(self):
378 def _convert_to_config(self):
378 """self.parsed_data->self.config"""
379 """self.parsed_data->self.config"""
379 for k, v in vars(self.parsed_data).iteritems():
380 for k, v in vars(self.parsed_data).iteritems():
380 exec_str = 'self.config.' + k + '= v'
381 exec_str = 'self.config.' + k + '= v'
381 exec exec_str in locals(), globals()
382 exec exec_str in locals(), globals()
382
383
383
384
@@ -1,1009 +1,1009 b''
1 """Analysis of text input into executable blocks.
1 """Analysis of text input into executable blocks.
2
2
3 The main class in this module, :class:`InputSplitter`, is designed to break
3 The main class in this module, :class:`InputSplitter`, is designed to break
4 input from either interactive, line-by-line environments or block-based ones,
4 input from either interactive, line-by-line environments or block-based ones,
5 into standalone blocks that can be executed by Python as 'single' statements
5 into standalone blocks that can be executed by Python as 'single' statements
6 (thus triggering sys.displayhook).
6 (thus triggering sys.displayhook).
7
7
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 with full support for the extended IPython syntax (magics, system calls, etc).
9 with full support for the extended IPython syntax (magics, system calls, etc).
10
10
11 For more details, see the class docstring below.
11 For more details, see the class docstring below.
12
12
13 Syntax Transformations
13 Syntax Transformations
14 ----------------------
14 ----------------------
15
15
16 One of the main jobs of the code in this file is to apply all syntax
16 One of the main jobs of the code in this file is to apply all syntax
17 transformations that make up 'the IPython language', i.e. magics, shell
17 transformations that make up 'the IPython language', i.e. magics, shell
18 escapes, etc. All transformations should be implemented as *fully stateless*
18 escapes, etc. All transformations should be implemented as *fully stateless*
19 entities, that simply take one line as their input and return a line.
19 entities, that simply take one line as their input and return a line.
20 Internally for implementation purposes they may be a normal function or a
20 Internally for implementation purposes they may be a normal function or a
21 callable object, but the only input they receive will be a single line and they
21 callable object, but the only input they receive will be a single line and they
22 should only return a line, without holding any data-dependent state between
22 should only return a line, without holding any data-dependent state between
23 calls.
23 calls.
24
24
25 As an example, the EscapedTransformer is a class so we can more clearly group
25 As an example, the EscapedTransformer is a class so we can more clearly group
26 together the functionality of dispatching to individual functions based on the
26 together the functionality of dispatching to individual functions based on the
27 starting escape character, but the only method for public use is its call
27 starting escape character, but the only method for public use is its call
28 method.
28 method.
29
29
30
30
31 ToDo
31 ToDo
32 ----
32 ----
33
33
34 - Should we make push() actually raise an exception once push_accepts_more()
34 - Should we make push() actually raise an exception once push_accepts_more()
35 returns False?
35 returns False?
36
36
37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
38 at least just attributes of a class so not really very exposed.
38 at least just attributes of a class so not really very exposed.
39
39
40 - Think about the best way to support dynamic things: automagic, autocall,
40 - Think about the best way to support dynamic things: automagic, autocall,
41 macros, etc.
41 macros, etc.
42
42
43 - Think of a better heuristic for the application of the transforms in
43 - Think of a better heuristic for the application of the transforms in
44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
45 track indentation change events (indent, dedent, nothing) and apply them only
45 track indentation change events (indent, dedent, nothing) and apply them only
46 if the indentation went up, but not otherwise.
46 if the indentation went up, but not otherwise.
47
47
48 - Think of the cleanest way for supporting user-specified transformations (the
48 - Think of the cleanest way for supporting user-specified transformations (the
49 user prefilters we had before).
49 user prefilters we had before).
50
50
51 Authors
51 Authors
52 -------
52 -------
53
53
54 * Fernando Perez
54 * Fernando Perez
55 * Brian Granger
55 * Brian Granger
56 """
56 """
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # Copyright (C) 2010 The IPython Development Team
58 # Copyright (C) 2010 The IPython Development Team
59 #
59 #
60 # Distributed under the terms of the BSD License. The full license is in
60 # Distributed under the terms of the BSD License. The full license is in
61 # the file COPYING, distributed as part of this software.
61 # the file COPYING, distributed as part of this software.
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 from __future__ import print_function
63 from __future__ import print_function
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # Imports
66 # Imports
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # stdlib
68 # stdlib
69 import ast
69 import ast
70 import codeop
70 import codeop
71 import re
71 import re
72 import sys
72 import sys
73
73
74 # IPython modules
74 # IPython modules
75 from IPython.utils.text import make_quoted_expr
75 from IPython.utils.text import make_quoted_expr
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Globals
78 # Globals
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 # The escape sequences that define the syntax transformations IPython will
81 # The escape sequences that define the syntax transformations IPython will
82 # apply to user input. These can NOT be just changed here: many regular
82 # apply to user input. These can NOT be just changed here: many regular
83 # expressions and other parts of the code may use their hardcoded values, and
83 # expressions and other parts of the code may use their hardcoded values, and
84 # for all intents and purposes they constitute the 'IPython syntax', so they
84 # for all intents and purposes they constitute the 'IPython syntax', so they
85 # should be considered fixed.
85 # should be considered fixed.
86
86
87 ESC_SHELL = '!' # Send line to underlying system shell
87 ESC_SHELL = '!' # Send line to underlying system shell
88 ESC_SH_CAP = '!!' # Send line to system shell and capture output
88 ESC_SH_CAP = '!!' # Send line to system shell and capture output
89 ESC_HELP = '?' # Find information about object
89 ESC_HELP = '?' # Find information about object
90 ESC_HELP2 = '??' # Find extra-detailed information about object
90 ESC_HELP2 = '??' # Find extra-detailed information about object
91 ESC_MAGIC = '%' # Call magic function
91 ESC_MAGIC = '%' # Call magic function
92 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
92 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
93 ESC_QUOTE2 = ';' # Quote all args as a single string, call
93 ESC_QUOTE2 = ';' # Quote all args as a single string, call
94 ESC_PAREN = '/' # Call first argument with rest of line as arguments
94 ESC_PAREN = '/' # Call first argument with rest of line as arguments
95
95
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 # Utilities
97 # Utilities
98 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
99
99
100 # FIXME: These are general-purpose utilities that later can be moved to the
100 # FIXME: These are general-purpose utilities that later can be moved to the
101 # general ward. Kept here for now because we're being very strict about test
101 # general ward. Kept here for now because we're being very strict about test
102 # coverage with this code, and this lets us ensure that we keep 100% coverage
102 # coverage with this code, and this lets us ensure that we keep 100% coverage
103 # while developing.
103 # while developing.
104
104
105 # compiled regexps for autoindent management
105 # compiled regexps for autoindent management
106 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
106 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
107 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
107 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
108
108
109 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
109 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
110 # before pure comments
110 # before pure comments
111 comment_line_re = re.compile('^\s*\#')
111 comment_line_re = re.compile('^\s*\#')
112
112
113
113
114 def num_ini_spaces(s):
114 def num_ini_spaces(s):
115 """Return the number of initial spaces in a string.
115 """Return the number of initial spaces in a string.
116
116
117 Note that tabs are counted as a single space. For now, we do *not* support
117 Note that tabs are counted as a single space. For now, we do *not* support
118 mixing of tabs and spaces in the user's input.
118 mixing of tabs and spaces in the user's input.
119
119
120 Parameters
120 Parameters
121 ----------
121 ----------
122 s : string
122 s : string
123
123
124 Returns
124 Returns
125 -------
125 -------
126 n : int
126 n : int
127 """
127 """
128
128
129 ini_spaces = ini_spaces_re.match(s)
129 ini_spaces = ini_spaces_re.match(s)
130 if ini_spaces:
130 if ini_spaces:
131 return ini_spaces.end()
131 return ini_spaces.end()
132 else:
132 else:
133 return 0
133 return 0
134
134
135
135
136 def remove_comments(src):
136 def remove_comments(src):
137 """Remove all comments from input source.
137 """Remove all comments from input source.
138
138
139 Note: comments are NOT recognized inside of strings!
139 Note: comments are NOT recognized inside of strings!
140
140
141 Parameters
141 Parameters
142 ----------
142 ----------
143 src : string
143 src : string
144 A single or multiline input string.
144 A single or multiline input string.
145
145
146 Returns
146 Returns
147 -------
147 -------
148 String with all Python comments removed.
148 String with all Python comments removed.
149 """
149 """
150
150
151 return re.sub('#.*', '', src)
151 return re.sub('#.*', '', src)
152
152
153
153
154 def get_input_encoding():
154 def get_input_encoding():
155 """Return the default standard input encoding.
155 """Return the default standard input encoding.
156
156
157 If sys.stdin has no encoding, 'ascii' is returned."""
157 If sys.stdin has no encoding, 'ascii' is returned."""
158 # There are strange environments for which sys.stdin.encoding is None. We
158 # There are strange environments for which sys.stdin.encoding is None. We
159 # ensure that a valid encoding is returned.
159 # ensure that a valid encoding is returned.
160 encoding = getattr(sys.stdin, 'encoding', None)
160 encoding = getattr(sys.stdin, 'encoding', None)
161 if encoding is None:
161 if encoding is None:
162 encoding = 'ascii'
162 encoding = 'ascii'
163 return encoding
163 return encoding
164
164
165 #-----------------------------------------------------------------------------
165 #-----------------------------------------------------------------------------
166 # Classes and functions for normal Python syntax handling
166 # Classes and functions for normal Python syntax handling
167 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
168
168
169 # HACK! This implementation, written by Robert K a while ago using the
169 # HACK! This implementation, written by Robert K a while ago using the
170 # compiler module, is more robust than the other one below, but it expects its
170 # compiler module, is more robust than the other one below, but it expects its
171 # input to be pure python (no ipython syntax). For now we're using it as a
171 # input to be pure python (no ipython syntax). For now we're using it as a
172 # second-pass splitter after the first pass transforms the input to pure
172 # second-pass splitter after the first pass transforms the input to pure
173 # python.
173 # python.
174
174
175 def split_blocks(python):
175 def split_blocks(python):
176 """ Split multiple lines of code into discrete commands that can be
176 """ Split multiple lines of code into discrete commands that can be
177 executed singly.
177 executed singly.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181 python : str
181 python : str
182 Pure, exec'able Python code.
182 Pure, exec'able Python code.
183
183
184 Returns
184 Returns
185 -------
185 -------
186 commands : list of str
186 commands : list of str
187 Separate commands that can be exec'ed independently.
187 Separate commands that can be exec'ed independently.
188 """
188 """
189 # compiler.parse treats trailing spaces after a newline as a
189 # compiler.parse treats trailing spaces after a newline as a
190 # SyntaxError. This is different than codeop.CommandCompiler, which
190 # SyntaxError. This is different than codeop.CommandCompiler, which
191 # will compile the trailng spaces just fine. We simply strip any
191 # will compile the trailng spaces just fine. We simply strip any
192 # trailing whitespace off. Passing a string with trailing whitespace
192 # trailing whitespace off. Passing a string with trailing whitespace
193 # to exec will fail however. There seems to be some inconsistency in
193 # to exec will fail however. There seems to be some inconsistency in
194 # how trailing whitespace is handled, but this seems to work.
194 # how trailing whitespace is handled, but this seems to work.
195 python_ori = python # save original in case we bail on error
195 python_ori = python # save original in case we bail on error
196 python = python.strip()
196 python = python.strip()
197
197
198 # The compiler module will parse the code into an abstract syntax tree.
198 # The compiler module will parse the code into an abstract syntax tree.
199 # This has a bug with str("a\nb"), but not str("""a\nb""")!!!
199 # This has a bug with str("a\nb"), but not str("""a\nb""")!!!
200 try:
200 try:
201 code_ast = ast.parse(python)
201 code_ast = ast.parse(python)
202 except:
202 except:
203 return [python_ori]
203 return [python_ori]
204
204
205 # Uncomment to help debug the ast tree
205 # Uncomment to help debug the ast tree
206 # for n in code_ast.body:
206 # for n in code_ast.body:
207 # print n.lineno,'->',n
207 # print n.lineno,'->',n
208
208
209 # Each separate command is available by iterating over ast.node. The
209 # Each separate command is available by iterating over ast.node. The
210 # lineno attribute is the line number (1-indexed) beginning the commands
210 # lineno attribute is the line number (1-indexed) beginning the commands
211 # suite.
211 # suite.
212 # lines ending with ";" yield a Discard Node that doesn't have a lineno
212 # lines ending with ";" yield a Discard Node that doesn't have a lineno
213 # attribute. These nodes can and should be discarded. But there are
213 # attribute. These nodes can and should be discarded. But there are
214 # other situations that cause Discard nodes that shouldn't be discarded.
214 # other situations that cause Discard nodes that shouldn't be discarded.
215 # We might eventually discover other cases where lineno is None and have
215 # We might eventually discover other cases where lineno is None and have
216 # to put in a more sophisticated test.
216 # to put in a more sophisticated test.
217 linenos = [x.lineno-1 for x in code_ast.body if x.lineno is not None]
217 linenos = [x.lineno-1 for x in code_ast.body if x.lineno is not None]
218
218
219 # When we finally get the slices, we will need to slice all the way to
219 # When we finally get the slices, we will need to slice all the way to
220 # the end even though we don't have a line number for it. Fortunately,
220 # the end even though we don't have a line number for it. Fortunately,
221 # None does the job nicely.
221 # None does the job nicely.
222 linenos.append(None)
222 linenos.append(None)
223
223
224 # Same problem at the other end: sometimes the ast tree has its
224 # Same problem at the other end: sometimes the ast tree has its
225 # first complete statement not starting on line 0. In this case
225 # first complete statement not starting on line 0. In this case
226 # we might miss part of it. This fixes ticket 266993. Thanks Gael!
226 # we might miss part of it. This fixes ticket 266993. Thanks Gael!
227 linenos[0] = 0
227 linenos[0] = 0
228
228
229 lines = python.splitlines()
229 lines = python.splitlines()
230
230
231 # Create a list of atomic commands.
231 # Create a list of atomic commands.
232 cmds = []
232 cmds = []
233 for i, j in zip(linenos[:-1], linenos[1:]):
233 for i, j in zip(linenos[:-1], linenos[1:]):
234 cmd = lines[i:j]
234 cmd = lines[i:j]
235 if cmd:
235 if cmd:
236 cmds.append('\n'.join(cmd)+'\n')
236 cmds.append('\n'.join(cmd)+'\n')
237
237
238 return cmds
238 return cmds
239
239
240
240
241 class InputSplitter(object):
241 class InputSplitter(object):
242 """An object that can split Python source input in executable blocks.
242 """An object that can split Python source input in executable blocks.
243
243
244 This object is designed to be used in one of two basic modes:
244 This object is designed to be used in one of two basic modes:
245
245
246 1. By feeding it python source line-by-line, using :meth:`push`. In this
246 1. By feeding it python source line-by-line, using :meth:`push`. In this
247 mode, it will return on each push whether the currently pushed code
247 mode, it will return on each push whether the currently pushed code
248 could be executed already. In addition, it provides a method called
248 could be executed already. In addition, it provides a method called
249 :meth:`push_accepts_more` that can be used to query whether more input
249 :meth:`push_accepts_more` that can be used to query whether more input
250 can be pushed into a single interactive block.
250 can be pushed into a single interactive block.
251
251
252 2. By calling :meth:`split_blocks` with a single, multiline Python string,
252 2. By calling :meth:`split_blocks` with a single, multiline Python string,
253 that is then split into blocks each of which can be executed
253 that is then split into blocks each of which can be executed
254 interactively as a single statement.
254 interactively as a single statement.
255
255
256 This is a simple example of how an interactive terminal-based client can use
256 This is a simple example of how an interactive terminal-based client can use
257 this tool::
257 this tool::
258
258
259 isp = InputSplitter()
259 isp = InputSplitter()
260 while isp.push_accepts_more():
260 while isp.push_accepts_more():
261 indent = ' '*isp.indent_spaces
261 indent = ' '*isp.indent_spaces
262 prompt = '>>> ' + indent
262 prompt = '>>> ' + indent
263 line = indent + raw_input(prompt)
263 line = indent + raw_input(prompt)
264 isp.push(line)
264 isp.push(line)
265 print 'Input source was:\n', isp.source_reset(),
265 print 'Input source was:\n', isp.source_reset(),
266 """
266 """
267 # Number of spaces of indentation computed from input that has been pushed
267 # Number of spaces of indentation computed from input that has been pushed
268 # so far. This is the attributes callers should query to get the current
268 # so far. This is the attributes callers should query to get the current
269 # indentation level, in order to provide auto-indent facilities.
269 # indentation level, in order to provide auto-indent facilities.
270 indent_spaces = 0
270 indent_spaces = 0
271 # String, indicating the default input encoding. It is computed by default
271 # String, indicating the default input encoding. It is computed by default
272 # at initialization time via get_input_encoding(), but it can be reset by a
272 # at initialization time via get_input_encoding(), but it can be reset by a
273 # client with specific knowledge of the encoding.
273 # client with specific knowledge of the encoding.
274 encoding = ''
274 encoding = ''
275 # String where the current full source input is stored, properly encoded.
275 # String where the current full source input is stored, properly encoded.
276 # Reading this attribute is the normal way of querying the currently pushed
276 # Reading this attribute is the normal way of querying the currently pushed
277 # source code, that has been properly encoded.
277 # source code, that has been properly encoded.
278 source = ''
278 source = ''
279 # Code object corresponding to the current source. It is automatically
279 # Code object corresponding to the current source. It is automatically
280 # synced to the source, so it can be queried at any time to obtain the code
280 # synced to the source, so it can be queried at any time to obtain the code
281 # object; it will be None if the source doesn't compile to valid Python.
281 # object; it will be None if the source doesn't compile to valid Python.
282 code = None
282 code = None
283 # Input mode
283 # Input mode
284 input_mode = 'line'
284 input_mode = 'line'
285
285
286 # Private attributes
286 # Private attributes
287
287
288 # List with lines of input accumulated so far
288 # List with lines of input accumulated so far
289 _buffer = None
289 _buffer = None
290 # Command compiler
290 # Command compiler
291 _compile = None
291 _compile = None
292 # Mark when input has changed indentation all the way back to flush-left
292 # Mark when input has changed indentation all the way back to flush-left
293 _full_dedent = False
293 _full_dedent = False
294 # Boolean indicating whether the current block is complete
294 # Boolean indicating whether the current block is complete
295 _is_complete = None
295 _is_complete = None
296
296
297 def __init__(self, input_mode=None):
297 def __init__(self, input_mode=None):
298 """Create a new InputSplitter instance.
298 """Create a new InputSplitter instance.
299
299
300 Parameters
300 Parameters
301 ----------
301 ----------
302 input_mode : str
302 input_mode : str
303
303
304 One of ['line', 'cell']; default is 'line'.
304 One of ['line', 'cell']; default is 'line'.
305
305
306 The input_mode parameter controls how new inputs are used when fed via
306 The input_mode parameter controls how new inputs are used when fed via
307 the :meth:`push` method:
307 the :meth:`push` method:
308
308
309 - 'line': meant for line-oriented clients, inputs are appended one at a
309 - 'line': meant for line-oriented clients, inputs are appended one at a
310 time to the internal buffer and the whole buffer is compiled.
310 time to the internal buffer and the whole buffer is compiled.
311
311
312 - 'cell': meant for clients that can edit multi-line 'cells' of text at
312 - 'cell': meant for clients that can edit multi-line 'cells' of text at
313 a time. A cell can contain one or more blocks that can be compile in
313 a time. A cell can contain one or more blocks that can be compile in
314 'single' mode by Python. In this mode, each new input new input
314 'single' mode by Python. In this mode, each new input new input
315 completely replaces all prior inputs. Cell mode is thus equivalent
315 completely replaces all prior inputs. Cell mode is thus equivalent
316 to prepending a full reset() to every push() call.
316 to prepending a full reset() to every push() call.
317 """
317 """
318 self._buffer = []
318 self._buffer = []
319 self._compile = codeop.CommandCompiler()
319 self._compile = codeop.CommandCompiler()
320 self.encoding = get_input_encoding()
320 self.encoding = get_input_encoding()
321 self.input_mode = InputSplitter.input_mode if input_mode is None \
321 self.input_mode = InputSplitter.input_mode if input_mode is None \
322 else input_mode
322 else input_mode
323
323
324 def reset(self):
324 def reset(self):
325 """Reset the input buffer and associated state."""
325 """Reset the input buffer and associated state."""
326 self.indent_spaces = 0
326 self.indent_spaces = 0
327 self._buffer[:] = []
327 self._buffer[:] = []
328 self.source = ''
328 self.source = ''
329 self.code = None
329 self.code = None
330 self._is_complete = False
330 self._is_complete = False
331 self._full_dedent = False
331 self._full_dedent = False
332
332
333 def source_reset(self):
333 def source_reset(self):
334 """Return the input source and perform a full reset.
334 """Return the input source and perform a full reset.
335 """
335 """
336 out = self.source
336 out = self.source
337 self.reset()
337 self.reset()
338 return out
338 return out
339
339
340 def push(self, lines):
340 def push(self, lines):
341 """Push one or more lines of input.
341 """Push one or more lines of input.
342
342
343 This stores the given lines and returns a status code indicating
343 This stores the given lines and returns a status code indicating
344 whether the code forms a complete Python block or not.
344 whether the code forms a complete Python block or not.
345
345
346 Any exceptions generated in compilation are swallowed, but if an
346 Any exceptions generated in compilation are swallowed, but if an
347 exception was produced, the method returns True.
347 exception was produced, the method returns True.
348
348
349 Parameters
349 Parameters
350 ----------
350 ----------
351 lines : string
351 lines : string
352 One or more lines of Python input.
352 One or more lines of Python input.
353
353
354 Returns
354 Returns
355 -------
355 -------
356 is_complete : boolean
356 is_complete : boolean
357 True if the current input source (the result of the current input
357 True if the current input source (the result of the current input
358 plus prior inputs) forms a complete Python execution block. Note that
358 plus prior inputs) forms a complete Python execution block. Note that
359 this value is also stored as a private attribute (_is_complete), so it
359 this value is also stored as a private attribute (_is_complete), so it
360 can be queried at any time.
360 can be queried at any time.
361 """
361 """
362 if self.input_mode == 'cell':
362 if self.input_mode == 'cell':
363 self.reset()
363 self.reset()
364
364
365 self._store(lines)
365 self._store(lines)
366 source = self.source
366 source = self.source
367
367
368 # Before calling _compile(), reset the code object to None so that if an
368 # Before calling _compile(), reset the code object to None so that if an
369 # exception is raised in compilation, we don't mislead by having
369 # exception is raised in compilation, we don't mislead by having
370 # inconsistent code/source attributes.
370 # inconsistent code/source attributes.
371 self.code, self._is_complete = None, None
371 self.code, self._is_complete = None, None
372
372
373 # Honor termination lines properly
373 # Honor termination lines properly
374 if source.rstrip().endswith('\\'):
374 if source.rstrip().endswith('\\'):
375 return False
375 return False
376
376
377 self._update_indent(lines)
377 self._update_indent(lines)
378 try:
378 try:
379 self.code = self._compile(source)
379 self.code = self._compile(source)
380 # Invalid syntax can produce any of a number of different errors from
380 # Invalid syntax can produce any of a number of different errors from
381 # inside the compiler, so we have to catch them all. Syntax errors
381 # inside the compiler, so we have to catch them all. Syntax errors
382 # immediately produce a 'ready' block, so the invalid Python can be
382 # immediately produce a 'ready' block, so the invalid Python can be
383 # sent to the kernel for evaluation with possible ipython
383 # sent to the kernel for evaluation with possible ipython
384 # special-syntax conversion.
384 # special-syntax conversion.
385 except (SyntaxError, OverflowError, ValueError, TypeError,
385 except (SyntaxError, OverflowError, ValueError, TypeError,
386 MemoryError):
386 MemoryError):
387 self._is_complete = True
387 self._is_complete = True
388 else:
388 else:
389 # Compilation didn't produce any exceptions (though it may not have
389 # Compilation didn't produce any exceptions (though it may not have
390 # given a complete code object)
390 # given a complete code object)
391 self._is_complete = self.code is not None
391 self._is_complete = self.code is not None
392
392
393 return self._is_complete
393 return self._is_complete
394
394
395 def push_accepts_more(self):
395 def push_accepts_more(self):
396 """Return whether a block of interactive input can accept more input.
396 """Return whether a block of interactive input can accept more input.
397
397
398 This method is meant to be used by line-oriented frontends, who need to
398 This method is meant to be used by line-oriented frontends, who need to
399 guess whether a block is complete or not based solely on prior and
399 guess whether a block is complete or not based solely on prior and
400 current input lines. The InputSplitter considers it has a complete
400 current input lines. The InputSplitter considers it has a complete
401 interactive block and will not accept more input only when either a
401 interactive block and will not accept more input only when either a
402 SyntaxError is raised, or *all* of the following are true:
402 SyntaxError is raised, or *all* of the following are true:
403
403
404 1. The input compiles to a complete statement.
404 1. The input compiles to a complete statement.
405
405
406 2. The indentation level is flush-left (because if we are indented,
406 2. The indentation level is flush-left (because if we are indented,
407 like inside a function definition or for loop, we need to keep
407 like inside a function definition or for loop, we need to keep
408 reading new input).
408 reading new input).
409
409
410 3. There is one extra line consisting only of whitespace.
410 3. There is one extra line consisting only of whitespace.
411
411
412 Because of condition #3, this method should be used only by
412 Because of condition #3, this method should be used only by
413 *line-oriented* frontends, since it means that intermediate blank lines
413 *line-oriented* frontends, since it means that intermediate blank lines
414 are not allowed in function definitions (or any other indented block).
414 are not allowed in function definitions (or any other indented block).
415
415
416 Block-oriented frontends that have a separate keyboard event to
416 Block-oriented frontends that have a separate keyboard event to
417 indicate execution should use the :meth:`split_blocks` method instead.
417 indicate execution should use the :meth:`split_blocks` method instead.
418
418
419 If the current input produces a syntax error, this method immediately
419 If the current input produces a syntax error, this method immediately
420 returns False but does *not* raise the syntax error exception, as
420 returns False but does *not* raise the syntax error exception, as
421 typically clients will want to send invalid syntax to an execution
421 typically clients will want to send invalid syntax to an execution
422 backend which might convert the invalid syntax into valid Python via
422 backend which might convert the invalid syntax into valid Python via
423 one of the dynamic IPython mechanisms.
423 one of the dynamic IPython mechanisms.
424 """
424 """
425
425
426 # With incomplete input, unconditionally accept more
426 # With incomplete input, unconditionally accept more
427 if not self._is_complete:
427 if not self._is_complete:
428 return True
428 return True
429
429
430 # If we already have complete input and we're flush left, the answer
430 # If we already have complete input and we're flush left, the answer
431 # depends. In line mode, if there hasn't been any indentation,
431 # depends. In line mode, if there hasn't been any indentation,
432 # that's it. If we've come back from some indentation, we need
432 # that's it. If we've come back from some indentation, we need
433 # the blank final line to finish.
433 # the blank final line to finish.
434 # In cell mode, we need to check how many blocks the input so far
434 # In cell mode, we need to check how many blocks the input so far
435 # compiles into, because if there's already more than one full
435 # compiles into, because if there's already more than one full
436 # independent block of input, then the client has entered full
436 # independent block of input, then the client has entered full
437 # 'cell' mode and is feeding lines that each is complete. In this
437 # 'cell' mode and is feeding lines that each is complete. In this
438 # case we should then keep accepting. The Qt terminal-like console
438 # case we should then keep accepting. The Qt terminal-like console
439 # does precisely this, to provide the convenience of terminal-like
439 # does precisely this, to provide the convenience of terminal-like
440 # input of single expressions, but allowing the user (with a
440 # input of single expressions, but allowing the user (with a
441 # separate keystroke) to switch to 'cell' mode and type multiple
441 # separate keystroke) to switch to 'cell' mode and type multiple
442 # expressions in one shot.
442 # expressions in one shot.
443 if self.indent_spaces==0:
443 if self.indent_spaces==0:
444 if self.input_mode=='line':
444 if self.input_mode=='line':
445 if not self._full_dedent:
445 if not self._full_dedent:
446 return False
446 return False
447 else:
447 else:
448 nblocks = len(split_blocks(''.join(self._buffer)))
448 nblocks = len(split_blocks(''.join(self._buffer)))
449 if nblocks==1:
449 if nblocks==1:
450 return False
450 return False
451
451
452 # When input is complete, then termination is marked by an extra blank
452 # When input is complete, then termination is marked by an extra blank
453 # line at the end.
453 # line at the end.
454 last_line = self.source.splitlines()[-1]
454 last_line = self.source.splitlines()[-1]
455 return bool(last_line and not last_line.isspace())
455 return bool(last_line and not last_line.isspace())
456
456
457 def split_blocks(self, lines):
457 def split_blocks(self, lines):
458 """Split a multiline string into multiple input blocks.
458 """Split a multiline string into multiple input blocks.
459
459
460 Note: this method starts by performing a full reset().
460 Note: this method starts by performing a full reset().
461
461
462 Parameters
462 Parameters
463 ----------
463 ----------
464 lines : str
464 lines : str
465 A possibly multiline string.
465 A possibly multiline string.
466
466
467 Returns
467 Returns
468 -------
468 -------
469 blocks : list
469 blocks : list
470 A list of strings, each possibly multiline. Each string corresponds
470 A list of strings, each possibly multiline. Each string corresponds
471 to a single block that can be compiled in 'single' mode (unless it
471 to a single block that can be compiled in 'single' mode (unless it
472 has a syntax error)."""
472 has a syntax error)."""
473
473
474 # This code is fairly delicate. If you make any changes here, make
474 # This code is fairly delicate. If you make any changes here, make
475 # absolutely sure that you do run the full test suite and ALL tests
475 # absolutely sure that you do run the full test suite and ALL tests
476 # pass.
476 # pass.
477
477
478 self.reset()
478 self.reset()
479 blocks = []
479 blocks = []
480
480
481 # Reversed copy so we can use pop() efficiently and consume the input
481 # Reversed copy so we can use pop() efficiently and consume the input
482 # as a stack
482 # as a stack
483 lines = lines.splitlines()[::-1]
483 lines = lines.splitlines()[::-1]
484 # Outer loop over all input
484 # Outer loop over all input
485 while lines:
485 while lines:
486 #print 'Current lines:', lines # dbg
486 #print 'Current lines:', lines # dbg
487 # Inner loop to build each block
487 # Inner loop to build each block
488 while True:
488 while True:
489 # Safety exit from inner loop
489 # Safety exit from inner loop
490 if not lines:
490 if not lines:
491 break
491 break
492 # Grab next line but don't push it yet
492 # Grab next line but don't push it yet
493 next_line = lines.pop()
493 next_line = lines.pop()
494 # Blank/empty lines are pushed as-is
494 # Blank/empty lines are pushed as-is
495 if not next_line or next_line.isspace():
495 if not next_line or next_line.isspace():
496 self.push(next_line)
496 self.push(next_line)
497 continue
497 continue
498
498
499 # Check indentation changes caused by the *next* line
499 # Check indentation changes caused by the *next* line
500 indent_spaces, _full_dedent = self._find_indent(next_line)
500 indent_spaces, _full_dedent = self._find_indent(next_line)
501
501
502 # If the next line causes a dedent, it can be for two differnt
502 # If the next line causes a dedent, it can be for two differnt
503 # reasons: either an explicit de-dent by the user or a
503 # reasons: either an explicit de-dent by the user or a
504 # return/raise/pass statement. These MUST be handled
504 # return/raise/pass statement. These MUST be handled
505 # separately:
505 # separately:
506 #
506 #
507 # 1. the first case is only detected when the actual explicit
507 # 1. the first case is only detected when the actual explicit
508 # dedent happens, and that would be the *first* line of a *new*
508 # dedent happens, and that would be the *first* line of a *new*
509 # block. Thus, we must put the line back into the input buffer
509 # block. Thus, we must put the line back into the input buffer
510 # so that it starts a new block on the next pass.
510 # so that it starts a new block on the next pass.
511 #
511 #
512 # 2. the second case is detected in the line before the actual
512 # 2. the second case is detected in the line before the actual
513 # dedent happens, so , we consume the line and we can break out
513 # dedent happens, so , we consume the line and we can break out
514 # to start a new block.
514 # to start a new block.
515
515
516 # Case 1, explicit dedent causes a break.
516 # Case 1, explicit dedent causes a break.
517 # Note: check that we weren't on the very last line, else we'll
517 # Note: check that we weren't on the very last line, else we'll
518 # enter an infinite loop adding/removing the last line.
518 # enter an infinite loop adding/removing the last line.
519 if _full_dedent and lines and not next_line.startswith(' '):
519 if _full_dedent and lines and not next_line.startswith(' '):
520 lines.append(next_line)
520 lines.append(next_line)
521 break
521 break
522
522
523 # Otherwise any line is pushed
523 # Otherwise any line is pushed
524 self.push(next_line)
524 self.push(next_line)
525
525
526 # Case 2, full dedent with full block ready:
526 # Case 2, full dedent with full block ready:
527 if _full_dedent or \
527 if _full_dedent or \
528 self.indent_spaces==0 and not self.push_accepts_more():
528 self.indent_spaces==0 and not self.push_accepts_more():
529 break
529 break
530 # Form the new block with the current source input
530 # Form the new block with the current source input
531 blocks.append(self.source_reset())
531 blocks.append(self.source_reset())
532
532
533 #return blocks
533 #return blocks
534 # HACK!!! Now that our input is in blocks but guaranteed to be pure
534 # HACK!!! Now that our input is in blocks but guaranteed to be pure
535 # python syntax, feed it back a second time through the AST-based
535 # python syntax, feed it back a second time through the AST-based
536 # splitter, which is more accurate than ours.
536 # splitter, which is more accurate than ours.
537 return split_blocks(''.join(blocks))
537 return split_blocks(''.join(blocks))
538
538
539 #------------------------------------------------------------------------
539 #------------------------------------------------------------------------
540 # Private interface
540 # Private interface
541 #------------------------------------------------------------------------
541 #------------------------------------------------------------------------
542
542
543 def _find_indent(self, line):
543 def _find_indent(self, line):
544 """Compute the new indentation level for a single line.
544 """Compute the new indentation level for a single line.
545
545
546 Parameters
546 Parameters
547 ----------
547 ----------
548 line : str
548 line : str
549 A single new line of non-whitespace, non-comment Python input.
549 A single new line of non-whitespace, non-comment Python input.
550
550
551 Returns
551 Returns
552 -------
552 -------
553 indent_spaces : int
553 indent_spaces : int
554 New value for the indent level (it may be equal to self.indent_spaces
554 New value for the indent level (it may be equal to self.indent_spaces
555 if indentation doesn't change.
555 if indentation doesn't change.
556
556
557 full_dedent : boolean
557 full_dedent : boolean
558 Whether the new line causes a full flush-left dedent.
558 Whether the new line causes a full flush-left dedent.
559 """
559 """
560 indent_spaces = self.indent_spaces
560 indent_spaces = self.indent_spaces
561 full_dedent = self._full_dedent
561 full_dedent = self._full_dedent
562
562
563 inisp = num_ini_spaces(line)
563 inisp = num_ini_spaces(line)
564 if inisp < indent_spaces:
564 if inisp < indent_spaces:
565 indent_spaces = inisp
565 indent_spaces = inisp
566 if indent_spaces <= 0:
566 if indent_spaces <= 0:
567 #print 'Full dedent in text',self.source # dbg
567 #print 'Full dedent in text',self.source # dbg
568 full_dedent = True
568 full_dedent = True
569
569
570 if line[-1] == ':':
570 if line[-1] == ':':
571 indent_spaces += 4
571 indent_spaces += 4
572 elif dedent_re.match(line):
572 elif dedent_re.match(line):
573 indent_spaces -= 4
573 indent_spaces -= 4
574 if indent_spaces <= 0:
574 if indent_spaces <= 0:
575 full_dedent = True
575 full_dedent = True
576
576
577 # Safety
577 # Safety
578 if indent_spaces < 0:
578 if indent_spaces < 0:
579 indent_spaces = 0
579 indent_spaces = 0
580 #print 'safety' # dbg
580 #print 'safety' # dbg
581
581
582 return indent_spaces, full_dedent
582 return indent_spaces, full_dedent
583
583
584 def _update_indent(self, lines):
584 def _update_indent(self, lines):
585 for line in remove_comments(lines).splitlines():
585 for line in remove_comments(lines).splitlines():
586 if line and not line.isspace():
586 if line and not line.isspace():
587 self.indent_spaces, self._full_dedent = self._find_indent(line)
587 self.indent_spaces, self._full_dedent = self._find_indent(line)
588
588
589 def _store(self, lines, buffer=None, store='source'):
589 def _store(self, lines, buffer=None, store='source'):
590 """Store one or more lines of input.
590 """Store one or more lines of input.
591
591
592 If input lines are not newline-terminated, a newline is automatically
592 If input lines are not newline-terminated, a newline is automatically
593 appended."""
593 appended."""
594
594
595 if buffer is None:
595 if buffer is None:
596 buffer = self._buffer
596 buffer = self._buffer
597
597
598 if lines.endswith('\n'):
598 if lines.endswith('\n'):
599 buffer.append(lines)
599 buffer.append(lines)
600 else:
600 else:
601 buffer.append(lines+'\n')
601 buffer.append(lines+'\n')
602 setattr(self, store, self._set_source(buffer))
602 setattr(self, store, self._set_source(buffer))
603
603
604 def _set_source(self, buffer):
604 def _set_source(self, buffer):
605 return u''.join(buffer)
605 return u''.join(buffer)
606
606
607
607
608 #-----------------------------------------------------------------------------
608 #-----------------------------------------------------------------------------
609 # Functions and classes for IPython-specific syntactic support
609 # Functions and classes for IPython-specific syntactic support
610 #-----------------------------------------------------------------------------
610 #-----------------------------------------------------------------------------
611
611
612 # RegExp for splitting line contents into pre-char//first word-method//rest.
612 # RegExp for splitting line contents into pre-char//first word-method//rest.
613 # For clarity, each group in on one line.
613 # For clarity, each group in on one line.
614
614
615 line_split = re.compile("""
615 line_split = re.compile("""
616 ^(\s*) # any leading space
616 ^(\s*) # any leading space
617 ([,;/%]|!!?|\?\??) # escape character or characters
617 ([,;/%]|!!?|\?\??) # escape character or characters
618 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
618 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
619 # to correctly treat things like '?%magic'
619 # to correctly treat things like '?%magic'
620 (\s+.*$|$) # rest of line
620 (\s+.*$|$) # rest of line
621 """, re.VERBOSE)
621 """, re.VERBOSE)
622
622
623
623
624 def split_user_input(line):
624 def split_user_input(line):
625 """Split user input into early whitespace, esc-char, function part and rest.
625 """Split user input into early whitespace, esc-char, function part and rest.
626
626
627 This is currently handles lines with '=' in them in a very inconsistent
627 This is currently handles lines with '=' in them in a very inconsistent
628 manner.
628 manner.
629
629
630 Examples
630 Examples
631 ========
631 ========
632 >>> split_user_input('x=1')
632 >>> split_user_input('x=1')
633 ('', '', 'x=1', '')
633 ('', '', 'x=1', '')
634 >>> split_user_input('?')
634 >>> split_user_input('?')
635 ('', '?', '', '')
635 ('', '?', '', '')
636 >>> split_user_input('??')
636 >>> split_user_input('??')
637 ('', '??', '', '')
637 ('', '??', '', '')
638 >>> split_user_input(' ?')
638 >>> split_user_input(' ?')
639 (' ', '?', '', '')
639 (' ', '?', '', '')
640 >>> split_user_input(' ??')
640 >>> split_user_input(' ??')
641 (' ', '??', '', '')
641 (' ', '??', '', '')
642 >>> split_user_input('??x')
642 >>> split_user_input('??x')
643 ('', '??', 'x', '')
643 ('', '??', 'x', '')
644 >>> split_user_input('?x=1')
644 >>> split_user_input('?x=1')
645 ('', '', '?x=1', '')
645 ('', '', '?x=1', '')
646 >>> split_user_input('!ls')
646 >>> split_user_input('!ls')
647 ('', '!', 'ls', '')
647 ('', '!', 'ls', '')
648 >>> split_user_input(' !ls')
648 >>> split_user_input(' !ls')
649 (' ', '!', 'ls', '')
649 (' ', '!', 'ls', '')
650 >>> split_user_input('!!ls')
650 >>> split_user_input('!!ls')
651 ('', '!!', 'ls', '')
651 ('', '!!', 'ls', '')
652 >>> split_user_input(' !!ls')
652 >>> split_user_input(' !!ls')
653 (' ', '!!', 'ls', '')
653 (' ', '!!', 'ls', '')
654 >>> split_user_input(',ls')
654 >>> split_user_input(',ls')
655 ('', ',', 'ls', '')
655 ('', ',', 'ls', '')
656 >>> split_user_input(';ls')
656 >>> split_user_input(';ls')
657 ('', ';', 'ls', '')
657 ('', ';', 'ls', '')
658 >>> split_user_input(' ;ls')
658 >>> split_user_input(' ;ls')
659 (' ', ';', 'ls', '')
659 (' ', ';', 'ls', '')
660 >>> split_user_input('f.g(x)')
660 >>> split_user_input('f.g(x)')
661 ('', '', 'f.g(x)', '')
661 ('', '', 'f.g(x)', '')
662 >>> split_user_input('f.g (x)')
662 >>> split_user_input('f.g (x)')
663 ('', '', 'f.g', '(x)')
663 ('', '', 'f.g', '(x)')
664 >>> split_user_input('?%hist')
664 >>> split_user_input('?%hist')
665 ('', '?', '%hist', '')
665 ('', '?', '%hist', '')
666 >>> split_user_input('?x*')
666 >>> split_user_input('?x*')
667 ('', '?', 'x*', '')
667 ('', '?', 'x*', '')
668 """
668 """
669 match = line_split.match(line)
669 match = line_split.match(line)
670 if match:
670 if match:
671 lspace, esc, fpart, rest = match.groups()
671 lspace, esc, fpart, rest = match.groups()
672 else:
672 else:
673 # print "match failed for line '%s'" % line
673 # print "match failed for line '%s'" % line
674 try:
674 try:
675 fpart, rest = line.split(None, 1)
675 fpart, rest = line.split(None, 1)
676 except ValueError:
676 except ValueError:
677 # print "split failed for line '%s'" % line
677 # print "split failed for line '%s'" % line
678 fpart, rest = line,''
678 fpart, rest = line,''
679 lspace = re.match('^(\s*)(.*)', line).groups()[0]
679 lspace = re.match('^(\s*)(.*)', line).groups()[0]
680 esc = ''
680 esc = ''
681
681
682 # fpart has to be a valid python identifier, so it better be only pure
682 # fpart has to be a valid python identifier, so it better be only pure
683 # ascii, no unicode:
683 # ascii, no unicode:
684 try:
684 try:
685 fpart = fpart.encode('ascii')
685 fpart = fpart.encode('ascii')
686 except UnicodeEncodeError:
686 except UnicodeEncodeError:
687 lspace = unicode(lspace)
687 lspace = unicode(lspace)
688 rest = fpart + u' ' + rest
688 rest = fpart + u' ' + rest
689 fpart = u''
689 fpart = u''
690
690
691 #print 'line:<%s>' % line # dbg
691 #print 'line:<%s>' % line # dbg
692 #print 'esc <%s> fpart <%s> rest <%s>' % (esc,fpart.strip(),rest) # dbg
692 #print 'esc <%s> fpart <%s> rest <%s>' % (esc,fpart.strip(),rest) # dbg
693 return lspace, esc, fpart.strip(), rest.lstrip()
693 return lspace, esc, fpart.strip(), rest.lstrip()
694
694
695
695
696 # The escaped translators ALL receive a line where their own escape has been
696 # The escaped translators ALL receive a line where their own escape has been
697 # stripped. Only '?' is valid at the end of the line, all others can only be
697 # stripped. Only '?' is valid at the end of the line, all others can only be
698 # placed at the start.
698 # placed at the start.
699
699
700 class LineInfo(object):
700 class LineInfo(object):
701 """A single line of input and associated info.
701 """A single line of input and associated info.
702
702
703 This is a utility class that mostly wraps the output of
703 This is a utility class that mostly wraps the output of
704 :func:`split_user_input` into a convenient object to be passed around
704 :func:`split_user_input` into a convenient object to be passed around
705 during input transformations.
705 during input transformations.
706
706
707 Includes the following as properties:
707 Includes the following as properties:
708
708
709 line
709 line
710 The original, raw line
710 The original, raw line
711
711
712 lspace
712 lspace
713 Any early whitespace before actual text starts.
713 Any early whitespace before actual text starts.
714
714
715 esc
715 esc
716 The initial esc character (or characters, for double-char escapes like
716 The initial esc character (or characters, for double-char escapes like
717 '??' or '!!').
717 '??' or '!!').
718
718
719 fpart
719 fpart
720 The 'function part', which is basically the maximal initial sequence
720 The 'function part', which is basically the maximal initial sequence
721 of valid python identifiers and the '.' character. This is what is
721 of valid python identifiers and the '.' character. This is what is
722 checked for alias and magic transformations, used for auto-calling,
722 checked for alias and magic transformations, used for auto-calling,
723 etc.
723 etc.
724
724
725 rest
725 rest
726 Everything else on the line.
726 Everything else on the line.
727 """
727 """
728 def __init__(self, line):
728 def __init__(self, line):
729 self.line = line
729 self.line = line
730 self.lspace, self.esc, self.fpart, self.rest = \
730 self.lspace, self.esc, self.fpart, self.rest = \
731 split_user_input(line)
731 split_user_input(line)
732
732
733 def __str__(self):
733 def __str__(self):
734 return "LineInfo [%s|%s|%s|%s]" % (self.lspace, self.esc,
734 return "LineInfo [%s|%s|%s|%s]" % (self.lspace, self.esc,
735 self.fpart, self.rest)
735 self.fpart, self.rest)
736
736
737
737
738 # Transformations of the special syntaxes that don't rely on an explicit escape
738 # Transformations of the special syntaxes that don't rely on an explicit escape
739 # character but instead on patterns on the input line
739 # character but instead on patterns on the input line
740
740
741 # The core transformations are implemented as standalone functions that can be
741 # The core transformations are implemented as standalone functions that can be
742 # tested and validated in isolation. Each of these uses a regexp, we
742 # tested and validated in isolation. Each of these uses a regexp, we
743 # pre-compile these and keep them close to each function definition for clarity
743 # pre-compile these and keep them close to each function definition for clarity
744
744
745 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
745 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
746 r'\s*=\s*!\s*(?P<cmd>.*)')
746 r'\s*=\s*!\s*(?P<cmd>.*)')
747
747
748 def transform_assign_system(line):
748 def transform_assign_system(line):
749 """Handle the `files = !ls` syntax."""
749 """Handle the `files = !ls` syntax."""
750 m = _assign_system_re.match(line)
750 m = _assign_system_re.match(line)
751 if m is not None:
751 if m is not None:
752 cmd = m.group('cmd')
752 cmd = m.group('cmd')
753 lhs = m.group('lhs')
753 lhs = m.group('lhs')
754 expr = make_quoted_expr(cmd)
754 expr = make_quoted_expr(cmd)
755 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
755 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
756 return new_line
756 return new_line
757 return line
757 return line
758
758
759
759
760 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
760 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
761 r'\s*=\s*%\s*(?P<cmd>.*)')
761 r'\s*=\s*%\s*(?P<cmd>.*)')
762
762
763 def transform_assign_magic(line):
763 def transform_assign_magic(line):
764 """Handle the `a = %who` syntax."""
764 """Handle the `a = %who` syntax."""
765 m = _assign_magic_re.match(line)
765 m = _assign_magic_re.match(line)
766 if m is not None:
766 if m is not None:
767 cmd = m.group('cmd')
767 cmd = m.group('cmd')
768 lhs = m.group('lhs')
768 lhs = m.group('lhs')
769 expr = make_quoted_expr(cmd)
769 expr = make_quoted_expr(cmd)
770 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
770 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
771 return new_line
771 return new_line
772 return line
772 return line
773
773
774
774
775 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
775 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
776
776
777 def transform_classic_prompt(line):
777 def transform_classic_prompt(line):
778 """Handle inputs that start with '>>> ' syntax."""
778 """Handle inputs that start with '>>> ' syntax."""
779
779
780 if not line or line.isspace():
780 if not line or line.isspace():
781 return line
781 return line
782 m = _classic_prompt_re.match(line)
782 m = _classic_prompt_re.match(line)
783 if m:
783 if m:
784 return line[len(m.group(0)):]
784 return line[len(m.group(0)):]
785 else:
785 else:
786 return line
786 return line
787
787
788
788
789 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
789 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
790
790
791 def transform_ipy_prompt(line):
791 def transform_ipy_prompt(line):
792 """Handle inputs that start classic IPython prompt syntax."""
792 """Handle inputs that start classic IPython prompt syntax."""
793
793
794 if not line or line.isspace():
794 if not line or line.isspace():
795 return line
795 return line
796 #print 'LINE: %r' % line # dbg
796 #print 'LINE: %r' % line # dbg
797 m = _ipy_prompt_re.match(line)
797 m = _ipy_prompt_re.match(line)
798 if m:
798 if m:
799 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
799 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
800 return line[len(m.group(0)):]
800 return line[len(m.group(0)):]
801 else:
801 else:
802 return line
802 return line
803
803
804
804
805 class EscapedTransformer(object):
805 class EscapedTransformer(object):
806 """Class to transform lines that are explicitly escaped out."""
806 """Class to transform lines that are explicitly escaped out."""
807
807
808 def __init__(self):
808 def __init__(self):
809 tr = { ESC_SHELL : self._tr_system,
809 tr = { ESC_SHELL : self._tr_system,
810 ESC_SH_CAP : self._tr_system2,
810 ESC_SH_CAP : self._tr_system2,
811 ESC_HELP : self._tr_help,
811 ESC_HELP : self._tr_help,
812 ESC_HELP2 : self._tr_help,
812 ESC_HELP2 : self._tr_help,
813 ESC_MAGIC : self._tr_magic,
813 ESC_MAGIC : self._tr_magic,
814 ESC_QUOTE : self._tr_quote,
814 ESC_QUOTE : self._tr_quote,
815 ESC_QUOTE2 : self._tr_quote2,
815 ESC_QUOTE2 : self._tr_quote2,
816 ESC_PAREN : self._tr_paren }
816 ESC_PAREN : self._tr_paren }
817 self.tr = tr
817 self.tr = tr
818
818
819 # Support for syntax transformations that use explicit escapes typed by the
819 # Support for syntax transformations that use explicit escapes typed by the
820 # user at the beginning of a line
820 # user at the beginning of a line
821 @staticmethod
821 @staticmethod
822 def _tr_system(line_info):
822 def _tr_system(line_info):
823 "Translate lines escaped with: !"
823 "Translate lines escaped with: !"
824 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
824 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
825 return '%sget_ipython().system(%s)' % (line_info.lspace,
825 return '%sget_ipython().system(%s)' % (line_info.lspace,
826 make_quoted_expr(cmd))
826 make_quoted_expr(cmd))
827
827
828 @staticmethod
828 @staticmethod
829 def _tr_system2(line_info):
829 def _tr_system2(line_info):
830 "Translate lines escaped with: !!"
830 "Translate lines escaped with: !!"
831 cmd = line_info.line.lstrip()[2:]
831 cmd = line_info.line.lstrip()[2:]
832 return '%sget_ipython().getoutput(%s)' % (line_info.lspace,
832 return '%sget_ipython().getoutput(%s)' % (line_info.lspace,
833 make_quoted_expr(cmd))
833 make_quoted_expr(cmd))
834
834
835 @staticmethod
835 @staticmethod
836 def _tr_help(line_info):
836 def _tr_help(line_info):
837 "Translate lines escaped with: ?/??"
837 "Translate lines escaped with: ?/??"
838 # A naked help line should just fire the intro help screen
838 # A naked help line should just fire the intro help screen
839 if not line_info.line[1:]:
839 if not line_info.line[1:]:
840 return 'get_ipython().show_usage()'
840 return 'get_ipython().show_usage()'
841
841
842 # There may be one or two '?' at the end, move them to the front so that
842 # There may be one or two '?' at the end, move them to the front so that
843 # the rest of the logic can assume escapes are at the start
843 # the rest of the logic can assume escapes are at the start
844 l_ori = line_info
844 l_ori = line_info
845 line = line_info.line
845 line = line_info.line
846 if line.endswith('?'):
846 if line.endswith('?'):
847 line = line[-1] + line[:-1]
847 line = line[-1] + line[:-1]
848 if line.endswith('?'):
848 if line.endswith('?'):
849 line = line[-1] + line[:-1]
849 line = line[-1] + line[:-1]
850 line_info = LineInfo(line)
850 line_info = LineInfo(line)
851
851
852 # From here on, simply choose which level of detail to get, and
852 # From here on, simply choose which level of detail to get, and
853 # special-case the psearch syntax
853 # special-case the psearch syntax
854 pinfo = 'pinfo' # default
854 pinfo = 'pinfo' # default
855 if '*' in line_info.line:
855 if '*' in line_info.line:
856 pinfo = 'psearch'
856 pinfo = 'psearch'
857 elif line_info.esc == '??':
857 elif line_info.esc == '??':
858 pinfo = 'pinfo2'
858 pinfo = 'pinfo2'
859
859
860 tpl = '%sget_ipython().magic("%s %s")'
860 tpl = '%sget_ipython().magic(u"%s %s")'
861 return tpl % (line_info.lspace, pinfo,
861 return tpl % (line_info.lspace, pinfo,
862 ' '.join([line_info.fpart, line_info.rest]).strip())
862 ' '.join([line_info.fpart, line_info.rest]).strip())
863
863
864 @staticmethod
864 @staticmethod
865 def _tr_magic(line_info):
865 def _tr_magic(line_info):
866 "Translate lines escaped with: %"
866 "Translate lines escaped with: %"
867 tpl = '%sget_ipython().magic(%s)'
867 tpl = '%sget_ipython().magic(%s)'
868 cmd = make_quoted_expr(' '.join([line_info.fpart,
868 cmd = make_quoted_expr(' '.join([line_info.fpart,
869 line_info.rest]).strip())
869 line_info.rest]).strip())
870 return tpl % (line_info.lspace, cmd)
870 return tpl % (line_info.lspace, cmd)
871
871
872 @staticmethod
872 @staticmethod
873 def _tr_quote(line_info):
873 def _tr_quote(line_info):
874 "Translate lines escaped with: ,"
874 "Translate lines escaped with: ,"
875 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
875 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
876 '", "'.join(line_info.rest.split()) )
876 '", "'.join(line_info.rest.split()) )
877
877
878 @staticmethod
878 @staticmethod
879 def _tr_quote2(line_info):
879 def _tr_quote2(line_info):
880 "Translate lines escaped with: ;"
880 "Translate lines escaped with: ;"
881 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
881 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
882 line_info.rest)
882 line_info.rest)
883
883
884 @staticmethod
884 @staticmethod
885 def _tr_paren(line_info):
885 def _tr_paren(line_info):
886 "Translate lines escaped with: /"
886 "Translate lines escaped with: /"
887 return '%s%s(%s)' % (line_info.lspace, line_info.fpart,
887 return '%s%s(%s)' % (line_info.lspace, line_info.fpart,
888 ", ".join(line_info.rest.split()))
888 ", ".join(line_info.rest.split()))
889
889
890 def __call__(self, line):
890 def __call__(self, line):
891 """Class to transform lines that are explicitly escaped out.
891 """Class to transform lines that are explicitly escaped out.
892
892
893 This calls the above _tr_* static methods for the actual line
893 This calls the above _tr_* static methods for the actual line
894 translations."""
894 translations."""
895
895
896 # Empty lines just get returned unmodified
896 # Empty lines just get returned unmodified
897 if not line or line.isspace():
897 if not line or line.isspace():
898 return line
898 return line
899
899
900 # Get line endpoints, where the escapes can be
900 # Get line endpoints, where the escapes can be
901 line_info = LineInfo(line)
901 line_info = LineInfo(line)
902
902
903 # If the escape is not at the start, only '?' needs to be special-cased.
903 # If the escape is not at the start, only '?' needs to be special-cased.
904 # All other escapes are only valid at the start
904 # All other escapes are only valid at the start
905 if not line_info.esc in self.tr:
905 if not line_info.esc in self.tr:
906 if line.endswith(ESC_HELP):
906 if line.endswith(ESC_HELP):
907 return self._tr_help(line_info)
907 return self._tr_help(line_info)
908 else:
908 else:
909 # If we don't recognize the escape, don't modify the line
909 # If we don't recognize the escape, don't modify the line
910 return line
910 return line
911
911
912 return self.tr[line_info.esc](line_info)
912 return self.tr[line_info.esc](line_info)
913
913
914
914
915 # A function-looking object to be used by the rest of the code. The purpose of
915 # A function-looking object to be used by the rest of the code. The purpose of
916 # the class in this case is to organize related functionality, more than to
916 # the class in this case is to organize related functionality, more than to
917 # manage state.
917 # manage state.
918 transform_escaped = EscapedTransformer()
918 transform_escaped = EscapedTransformer()
919
919
920
920
921 class IPythonInputSplitter(InputSplitter):
921 class IPythonInputSplitter(InputSplitter):
922 """An input splitter that recognizes all of IPython's special syntax."""
922 """An input splitter that recognizes all of IPython's special syntax."""
923
923
924 # String with raw, untransformed input.
924 # String with raw, untransformed input.
925 source_raw = ''
925 source_raw = ''
926
926
927 # Private attributes
927 # Private attributes
928
928
929 # List with lines of raw input accumulated so far.
929 # List with lines of raw input accumulated so far.
930 _buffer_raw = None
930 _buffer_raw = None
931
931
932 def __init__(self, input_mode=None):
932 def __init__(self, input_mode=None):
933 InputSplitter.__init__(self, input_mode)
933 InputSplitter.__init__(self, input_mode)
934 self._buffer_raw = []
934 self._buffer_raw = []
935
935
936 def reset(self):
936 def reset(self):
937 """Reset the input buffer and associated state."""
937 """Reset the input buffer and associated state."""
938 InputSplitter.reset(self)
938 InputSplitter.reset(self)
939 self._buffer_raw[:] = []
939 self._buffer_raw[:] = []
940 self.source_raw = ''
940 self.source_raw = ''
941
941
942 def source_raw_reset(self):
942 def source_raw_reset(self):
943 """Return input and raw source and perform a full reset.
943 """Return input and raw source and perform a full reset.
944 """
944 """
945 out = self.source
945 out = self.source
946 out_r = self.source_raw
946 out_r = self.source_raw
947 self.reset()
947 self.reset()
948 return out, out_r
948 return out, out_r
949
949
950 def push(self, lines):
950 def push(self, lines):
951 """Push one or more lines of IPython input.
951 """Push one or more lines of IPython input.
952 """
952 """
953 if not lines:
953 if not lines:
954 return super(IPythonInputSplitter, self).push(lines)
954 return super(IPythonInputSplitter, self).push(lines)
955
955
956 # We must ensure all input is pure unicode
956 # We must ensure all input is pure unicode
957 if type(lines)==str:
957 if type(lines)==str:
958 lines = lines.decode(self.encoding)
958 lines = lines.decode(self.encoding)
959
959
960 lines_list = lines.splitlines()
960 lines_list = lines.splitlines()
961
961
962 transforms = [transform_escaped, transform_assign_system,
962 transforms = [transform_escaped, transform_assign_system,
963 transform_assign_magic, transform_ipy_prompt,
963 transform_assign_magic, transform_ipy_prompt,
964 transform_classic_prompt]
964 transform_classic_prompt]
965
965
966 # Transform logic
966 # Transform logic
967 #
967 #
968 # We only apply the line transformers to the input if we have either no
968 # We only apply the line transformers to the input if we have either no
969 # input yet, or complete input, or if the last line of the buffer ends
969 # input yet, or complete input, or if the last line of the buffer ends
970 # with ':' (opening an indented block). This prevents the accidental
970 # with ':' (opening an indented block). This prevents the accidental
971 # transformation of escapes inside multiline expressions like
971 # transformation of escapes inside multiline expressions like
972 # triple-quoted strings or parenthesized expressions.
972 # triple-quoted strings or parenthesized expressions.
973 #
973 #
974 # The last heuristic, while ugly, ensures that the first line of an
974 # The last heuristic, while ugly, ensures that the first line of an
975 # indented block is correctly transformed.
975 # indented block is correctly transformed.
976 #
976 #
977 # FIXME: try to find a cleaner approach for this last bit.
977 # FIXME: try to find a cleaner approach for this last bit.
978
978
979 # If we were in 'block' mode, since we're going to pump the parent
979 # If we were in 'block' mode, since we're going to pump the parent
980 # class by hand line by line, we need to temporarily switch out to
980 # class by hand line by line, we need to temporarily switch out to
981 # 'line' mode, do a single manual reset and then feed the lines one
981 # 'line' mode, do a single manual reset and then feed the lines one
982 # by one. Note that this only matters if the input has more than one
982 # by one. Note that this only matters if the input has more than one
983 # line.
983 # line.
984 changed_input_mode = False
984 changed_input_mode = False
985
985
986 if self.input_mode == 'cell':
986 if self.input_mode == 'cell':
987 self.reset()
987 self.reset()
988 changed_input_mode = True
988 changed_input_mode = True
989 saved_input_mode = 'cell'
989 saved_input_mode = 'cell'
990 self.input_mode = 'line'
990 self.input_mode = 'line'
991
991
992 # Store raw source before applying any transformations to it. Note
992 # Store raw source before applying any transformations to it. Note
993 # that this must be done *after* the reset() call that would otherwise
993 # that this must be done *after* the reset() call that would otherwise
994 # flush the buffer.
994 # flush the buffer.
995 self._store(lines, self._buffer_raw, 'source_raw')
995 self._store(lines, self._buffer_raw, 'source_raw')
996
996
997 try:
997 try:
998 push = super(IPythonInputSplitter, self).push
998 push = super(IPythonInputSplitter, self).push
999 for line in lines_list:
999 for line in lines_list:
1000 if self._is_complete or not self._buffer or \
1000 if self._is_complete or not self._buffer or \
1001 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
1001 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
1002 for f in transforms:
1002 for f in transforms:
1003 line = f(line)
1003 line = f(line)
1004
1004
1005 out = push(line)
1005 out = push(line)
1006 finally:
1006 finally:
1007 if changed_input_mode:
1007 if changed_input_mode:
1008 self.input_mode = saved_input_mode
1008 self.input_mode = saved_input_mode
1009 return out
1009 return out
@@ -1,174 +1,174 b''
1 """Tests for input handlers.
1 """Tests for input handlers.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Module imports
4 # Module imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 # third party
7 # third party
8 import nose.tools as nt
8 import nose.tools as nt
9
9
10 # our own packages
10 # our own packages
11 from IPython.core import autocall
11 from IPython.core import autocall
12 from IPython.testing import decorators as dec
12 from IPython.testing import decorators as dec
13 from IPython.testing.globalipapp import get_ipython
13 from IPython.testing.globalipapp import get_ipython
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Globals
16 # Globals
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # Get the public instance of IPython
19 # Get the public instance of IPython
20 ip = get_ipython()
20 ip = get_ipython()
21
21
22 failures = []
22 failures = []
23 num_tests = 0
23 num_tests = 0
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Test functions
26 # Test functions
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 class CallableIndexable(object):
29 class CallableIndexable(object):
30 def __getitem__(self, idx): return True
30 def __getitem__(self, idx): return True
31 def __call__(self, *args, **kws): return True
31 def __call__(self, *args, **kws): return True
32
32
33
33
34 class Autocallable(autocall.IPyAutocall):
34 class Autocallable(autocall.IPyAutocall):
35 def __call__(self):
35 def __call__(self):
36 return "called"
36 return "called"
37
37
38
38
39 def run(tests):
39 def run(tests):
40 """Loop through a list of (pre, post) inputs, where pre is the string
40 """Loop through a list of (pre, post) inputs, where pre is the string
41 handed to ipython, and post is how that string looks after it's been
41 handed to ipython, and post is how that string looks after it's been
42 transformed (i.e. ipython's notion of _i)"""
42 transformed (i.e. ipython's notion of _i)"""
43 for pre, post in tests:
43 for pre, post in tests:
44 global num_tests
44 global num_tests
45 num_tests += 1
45 num_tests += 1
46 ip.runlines(pre)
46 ip.runlines(pre)
47 ip.runlines('_i') # Not sure why I need this...
47 ip.runlines('_i') # Not sure why I need this...
48 actual = ip.user_ns['_i']
48 actual = ip.user_ns['_i']
49 if actual != None:
49 if actual != None:
50 actual = actual.rstrip('\n')
50 actual = actual.rstrip('\n')
51 if actual != post:
51 if actual != post:
52 failures.append('Expected %r to become %r, found %r' % (
52 failures.append('Expected %r to become %r, found %r' % (
53 pre, post, actual))
53 pre, post, actual))
54
54
55
55
56 def test_handlers():
56 def test_handlers():
57 # alias expansion
57 # alias expansion
58
58
59 # We're using 'true' as our syscall of choice because it doesn't
59 # We're using 'true' as our syscall of choice because it doesn't
60 # write anything to stdout.
60 # write anything to stdout.
61
61
62 # Turn off actual execution of aliases, because it's noisy
62 # Turn off actual execution of aliases, because it's noisy
63 old_system_cmd = ip.system
63 old_system_cmd = ip.system
64 ip.system = lambda cmd: None
64 ip.system = lambda cmd: None
65
65
66
66
67 ip.alias_manager.alias_table['an_alias'] = (0, 'true')
67 ip.alias_manager.alias_table['an_alias'] = (0, 'true')
68 # These are useful for checking a particular recursive alias issue
68 # These are useful for checking a particular recursive alias issue
69 ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top')
69 ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top')
70 ip.alias_manager.alias_table['d'] = (0, 'true')
70 ip.alias_manager.alias_table['d'] = (0, 'true')
71 run([("an_alias", 'get_ipython().system("true ")'), # alias
71 run([("an_alias", 'get_ipython().system(u"true ")'), # alias
72 # Below: recursive aliases should expand whitespace-surrounded
72 # Below: recursive aliases should expand whitespace-surrounded
73 # chars, *not* initial chars which happen to be aliases:
73 # chars, *not* initial chars which happen to be aliases:
74 ("top", 'get_ipython().system("d:/cygwin/top ")'),
74 ("top", 'get_ipython().system(u"d:/cygwin/top ")'),
75 ])
75 ])
76 ip.system = old_system_cmd
76 ip.system = old_system_cmd
77
77
78 call_idx = CallableIndexable()
78 call_idx = CallableIndexable()
79 ip.user_ns['call_idx'] = call_idx
79 ip.user_ns['call_idx'] = call_idx
80
80
81 # For many of the below, we're also checking that leading whitespace
81 # For many of the below, we're also checking that leading whitespace
82 # turns off the esc char, which it should unless there is a continuation
82 # turns off the esc char, which it should unless there is a continuation
83 # line.
83 # line.
84 run([('"no change"', '"no change"'), # normal
84 run([('"no change"', '"no change"'), # normal
85 ("!true", 'get_ipython().system("true")'), # shell_escapes
85 ("!true", 'get_ipython().system(u"true")'), # shell_escapes
86 ("!! true", 'get_ipython().magic("sx true")'), # shell_escapes + magic
86 ("!! true", 'get_ipython().magic(u"sx true")'), # shell_escapes + magic
87 ("!!true", 'get_ipython().magic("sx true")'), # shell_escapes + magic
87 ("!!true", 'get_ipython().magic(u"sx true")'), # shell_escapes + magic
88 ("%lsmagic", 'get_ipython().magic("lsmagic ")'), # magic
88 ("%lsmagic", 'get_ipython().magic(u"lsmagic ")'), # magic
89 ("lsmagic", 'get_ipython().magic("lsmagic ")'), # magic
89 ("lsmagic", 'get_ipython().magic(u"lsmagic ")'), # magic
90 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
90 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
91
91
92 # post-esc-char whitespace goes inside
92 # post-esc-char whitespace goes inside
93 ("! true", 'get_ipython().system(" true")'),
93 ("! true", 'get_ipython().system(u" true")'),
94
94
95 # handle_help
95 # handle_help
96
96
97 # These are weak tests -- just looking at what the help handlers
97 # These are weak tests -- just looking at what the help handlers
98 # logs, which is not how it really does its work. But it still
98 # logs, which is not how it really does its work. But it still
99 # lets us check the key paths through the handler.
99 # lets us check the key paths through the handler.
100
100
101 ("x=1 # what?", "x=1 # what?"), # no help if valid python
101 ("x=1 # what?", "x=1 # what?"), # no help if valid python
102 ])
102 ])
103
103
104 # multi_line_specials
104 # multi_line_specials
105 ip.prefilter_manager.multi_line_specials = False
105 ip.prefilter_manager.multi_line_specials = False
106 # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion
106 # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion
107 run([
107 run([
108 ('if 1:\n !true', 'if 1:\n !true'),
108 ('if 1:\n !true', 'if 1:\n !true'),
109 ('if 1:\n lsmagic', 'if 1:\n lsmagic'),
109 ('if 1:\n lsmagic', 'if 1:\n lsmagic'),
110 ('if 1:\n an_alias', 'if 1:\n an_alias'),
110 ('if 1:\n an_alias', 'if 1:\n an_alias'),
111 ])
111 ])
112
112
113 ip.prefilter_manager.multi_line_specials = True
113 ip.prefilter_manager.multi_line_specials = True
114 # initial indents must be preserved.
114 # initial indents must be preserved.
115 run([
115 run([
116 ('if 1:\n !true', 'if 1:\n get_ipython().system("true")'),
116 ('if 1:\n !true', 'if 1:\n get_ipython().system(u"true")'),
117 ('if 2:\n lsmagic', 'if 2:\n get_ipython().magic("lsmagic ")'),
117 ('if 2:\n lsmagic', 'if 2:\n get_ipython().magic(u"lsmagic ")'),
118 ('if 1:\n an_alias', 'if 1:\n get_ipython().system("true ")'),
118 ('if 1:\n an_alias', 'if 1:\n get_ipython().system(u"true ")'),
119 # Weird one
119 # Weird one
120 ('if 1:\n !!true', 'if 1:\n get_ipython().magic("sx true")'),
120 ('if 1:\n !!true', 'if 1:\n get_ipython().magic(u"sx true")'),
121
121
122 # Even with m_l_s on, autocall is off even with special chars
122 # Even with m_l_s on, autocall is off even with special chars
123 ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
123 ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
124 ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'),
124 ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'),
125 ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'),
125 ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'),
126 ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'),
126 ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'),
127 # What about !!
127 # What about !!
128 ])
128 ])
129
129
130 # Objects which are instances of IPyAutocall are *always* autocalled
130 # Objects which are instances of IPyAutocall are *always* autocalled
131 autocallable = Autocallable()
131 autocallable = Autocallable()
132 ip.user_ns['autocallable'] = autocallable
132 ip.user_ns['autocallable'] = autocallable
133
133
134 # auto
134 # auto
135 ip.magic('autocall 0')
135 ip.magic('autocall 0')
136 # Only explicit escapes or instances of IPyAutocallable should get
136 # Only explicit escapes or instances of IPyAutocallable should get
137 # expanded
137 # expanded
138 run([
138 run([
139 ('len "abc"', 'len "abc"'),
139 ('len "abc"', 'len "abc"'),
140 ('autocallable', 'autocallable()'),
140 ('autocallable', 'autocallable()'),
141 (",list 1 2 3", 'list("1", "2", "3")'),
141 (",list 1 2 3", 'list("1", "2", "3")'),
142 (";list 1 2 3", 'list("1 2 3")'),
142 (";list 1 2 3", 'list("1 2 3")'),
143 ("/len range(1,4)", 'len(range(1,4))'),
143 ("/len range(1,4)", 'len(range(1,4))'),
144 ])
144 ])
145 ip.magic('autocall 1')
145 ip.magic('autocall 1')
146 run([
146 run([
147 (",list 1 2 3", 'list("1", "2", "3")'),
147 (",list 1 2 3", 'list("1", "2", "3")'),
148 (";list 1 2 3", 'list("1 2 3")'),
148 (";list 1 2 3", 'list("1 2 3")'),
149 ("/len range(1,4)", 'len(range(1,4))'),
149 ("/len range(1,4)", 'len(range(1,4))'),
150 ('len "abc"', 'len("abc")'),
150 ('len "abc"', 'len("abc")'),
151 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
151 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
152 # Autocall is turned off if first arg is [] and the object
152 # Autocall is turned off if first arg is [] and the object
153 # is both callable and indexable. Like so:
153 # is both callable and indexable. Like so:
154 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
154 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
155 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
155 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
156 ('call_idx 1', 'call_idx(1)'),
156 ('call_idx 1', 'call_idx(1)'),
157 ('len', 'len '), # only at 2 does it auto-call on single args
157 ('len', 'len '), # only at 2 does it auto-call on single args
158 ])
158 ])
159 ip.magic('autocall 2')
159 ip.magic('autocall 2')
160 run([
160 run([
161 (",list 1 2 3", 'list("1", "2", "3")'),
161 (",list 1 2 3", 'list("1", "2", "3")'),
162 (";list 1 2 3", 'list("1 2 3")'),
162 (";list 1 2 3", 'list("1 2 3")'),
163 ("/len range(1,4)", 'len(range(1,4))'),
163 ("/len range(1,4)", 'len(range(1,4))'),
164 ('len "abc"', 'len("abc")'),
164 ('len "abc"', 'len("abc")'),
165 ('len "abc";', 'len("abc");'),
165 ('len "abc";', 'len("abc");'),
166 ('len [1,2]', 'len([1,2])'),
166 ('len [1,2]', 'len([1,2])'),
167 ('call_idx [1]', 'call_idx [1]'),
167 ('call_idx [1]', 'call_idx [1]'),
168 ('call_idx 1', 'call_idx(1)'),
168 ('call_idx 1', 'call_idx(1)'),
169 # This is what's different:
169 # This is what's different:
170 ('len', 'len()'), # only at 2 does it auto-call on single args
170 ('len', 'len()'), # only at 2 does it auto-call on single args
171 ])
171 ])
172 ip.magic('autocall 1')
172 ip.magic('autocall 1')
173
173
174 nt.assert_equals(failures, [])
174 nt.assert_equals(failures, [])
@@ -1,704 +1,704 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the inputsplitter module.
2 """Tests for the inputsplitter module.
3
3
4 Authors
4 Authors
5 -------
5 -------
6 * Fernando Perez
6 * Fernando Perez
7 * Robert Kern
7 * Robert Kern
8 """
8 """
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
10 # Copyright (C) 2010 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # stdlib
19 # stdlib
20 import unittest
20 import unittest
21 import sys
21 import sys
22
22
23 # Third party
23 # Third party
24 import nose.tools as nt
24 import nose.tools as nt
25
25
26 # Our own
26 # Our own
27 from IPython.core import inputsplitter as isp
27 from IPython.core import inputsplitter as isp
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Semi-complete examples (also used as tests)
30 # Semi-complete examples (also used as tests)
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 # Note: at the bottom, there's a slightly more complete version of this that
33 # Note: at the bottom, there's a slightly more complete version of this that
34 # can be useful during development of code here.
34 # can be useful during development of code here.
35
35
36 def mini_interactive_loop(input_func):
36 def mini_interactive_loop(input_func):
37 """Minimal example of the logic of an interactive interpreter loop.
37 """Minimal example of the logic of an interactive interpreter loop.
38
38
39 This serves as an example, and it is used by the test system with a fake
39 This serves as an example, and it is used by the test system with a fake
40 raw_input that simulates interactive input."""
40 raw_input that simulates interactive input."""
41
41
42 from IPython.core.inputsplitter import InputSplitter
42 from IPython.core.inputsplitter import InputSplitter
43
43
44 isp = InputSplitter()
44 isp = InputSplitter()
45 # In practice, this input loop would be wrapped in an outside loop to read
45 # In practice, this input loop would be wrapped in an outside loop to read
46 # input indefinitely, until some exit/quit command was issued. Here we
46 # input indefinitely, until some exit/quit command was issued. Here we
47 # only illustrate the basic inner loop.
47 # only illustrate the basic inner loop.
48 while isp.push_accepts_more():
48 while isp.push_accepts_more():
49 indent = ' '*isp.indent_spaces
49 indent = ' '*isp.indent_spaces
50 prompt = '>>> ' + indent
50 prompt = '>>> ' + indent
51 line = indent + input_func(prompt)
51 line = indent + input_func(prompt)
52 isp.push(line)
52 isp.push(line)
53
53
54 # Here we just return input so we can use it in a test suite, but a real
54 # Here we just return input so we can use it in a test suite, but a real
55 # interpreter would instead send it for execution somewhere.
55 # interpreter would instead send it for execution somewhere.
56 src = isp.source_reset()
56 src = isp.source_reset()
57 #print 'Input source was:\n', src # dbg
57 #print 'Input source was:\n', src # dbg
58 return src
58 return src
59
59
60 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
61 # Test utilities, just for local use
61 # Test utilities, just for local use
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63
63
64 def assemble(block):
64 def assemble(block):
65 """Assemble a block into multi-line sub-blocks."""
65 """Assemble a block into multi-line sub-blocks."""
66 return ['\n'.join(sub_block)+'\n' for sub_block in block]
66 return ['\n'.join(sub_block)+'\n' for sub_block in block]
67
67
68
68
69 def pseudo_input(lines):
69 def pseudo_input(lines):
70 """Return a function that acts like raw_input but feeds the input list."""
70 """Return a function that acts like raw_input but feeds the input list."""
71 ilines = iter(lines)
71 ilines = iter(lines)
72 def raw_in(prompt):
72 def raw_in(prompt):
73 try:
73 try:
74 return next(ilines)
74 return next(ilines)
75 except StopIteration:
75 except StopIteration:
76 return ''
76 return ''
77 return raw_in
77 return raw_in
78
78
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80 # Tests
80 # Tests
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 def test_spaces():
82 def test_spaces():
83 tests = [('', 0),
83 tests = [('', 0),
84 (' ', 1),
84 (' ', 1),
85 ('\n', 0),
85 ('\n', 0),
86 (' \n', 1),
86 (' \n', 1),
87 ('x', 0),
87 ('x', 0),
88 (' x', 1),
88 (' x', 1),
89 (' x',2),
89 (' x',2),
90 (' x',4),
90 (' x',4),
91 # Note: tabs are counted as a single whitespace!
91 # Note: tabs are counted as a single whitespace!
92 ('\tx', 1),
92 ('\tx', 1),
93 ('\t x', 2),
93 ('\t x', 2),
94 ]
94 ]
95
95
96 for s, nsp in tests:
96 for s, nsp in tests:
97 nt.assert_equal(isp.num_ini_spaces(s), nsp)
97 nt.assert_equal(isp.num_ini_spaces(s), nsp)
98
98
99
99
100 def test_remove_comments():
100 def test_remove_comments():
101 tests = [('text', 'text'),
101 tests = [('text', 'text'),
102 ('text # comment', 'text '),
102 ('text # comment', 'text '),
103 ('text # comment\n', 'text \n'),
103 ('text # comment\n', 'text \n'),
104 ('text # comment \n', 'text \n'),
104 ('text # comment \n', 'text \n'),
105 ('line # c \nline\n','line \nline\n'),
105 ('line # c \nline\n','line \nline\n'),
106 ('line # c \nline#c2 \nline\nline #c\n\n',
106 ('line # c \nline#c2 \nline\nline #c\n\n',
107 'line \nline\nline\nline \n\n'),
107 'line \nline\nline\nline \n\n'),
108 ]
108 ]
109
109
110 for inp, out in tests:
110 for inp, out in tests:
111 nt.assert_equal(isp.remove_comments(inp), out)
111 nt.assert_equal(isp.remove_comments(inp), out)
112
112
113
113
114 def test_get_input_encoding():
114 def test_get_input_encoding():
115 encoding = isp.get_input_encoding()
115 encoding = isp.get_input_encoding()
116 nt.assert_true(isinstance(encoding, basestring))
116 nt.assert_true(isinstance(encoding, basestring))
117 # simple-minded check that at least encoding a simple string works with the
117 # simple-minded check that at least encoding a simple string works with the
118 # encoding we got.
118 # encoding we got.
119 nt.assert_equal('test'.encode(encoding), 'test')
119 nt.assert_equal('test'.encode(encoding), 'test')
120
120
121
121
122 class NoInputEncodingTestCase(unittest.TestCase):
122 class NoInputEncodingTestCase(unittest.TestCase):
123 def setUp(self):
123 def setUp(self):
124 self.old_stdin = sys.stdin
124 self.old_stdin = sys.stdin
125 class X: pass
125 class X: pass
126 fake_stdin = X()
126 fake_stdin = X()
127 sys.stdin = fake_stdin
127 sys.stdin = fake_stdin
128
128
129 def test(self):
129 def test(self):
130 # Verify that if sys.stdin has no 'encoding' attribute we do the right
130 # Verify that if sys.stdin has no 'encoding' attribute we do the right
131 # thing
131 # thing
132 enc = isp.get_input_encoding()
132 enc = isp.get_input_encoding()
133 self.assertEqual(enc, 'ascii')
133 self.assertEqual(enc, 'ascii')
134
134
135 def tearDown(self):
135 def tearDown(self):
136 sys.stdin = self.old_stdin
136 sys.stdin = self.old_stdin
137
137
138
138
139 class InputSplitterTestCase(unittest.TestCase):
139 class InputSplitterTestCase(unittest.TestCase):
140 def setUp(self):
140 def setUp(self):
141 self.isp = isp.InputSplitter()
141 self.isp = isp.InputSplitter()
142
142
143 def test_reset(self):
143 def test_reset(self):
144 isp = self.isp
144 isp = self.isp
145 isp.push('x=1')
145 isp.push('x=1')
146 isp.reset()
146 isp.reset()
147 self.assertEqual(isp._buffer, [])
147 self.assertEqual(isp._buffer, [])
148 self.assertEqual(isp.indent_spaces, 0)
148 self.assertEqual(isp.indent_spaces, 0)
149 self.assertEqual(isp.source, '')
149 self.assertEqual(isp.source, '')
150 self.assertEqual(isp.code, None)
150 self.assertEqual(isp.code, None)
151 self.assertEqual(isp._is_complete, False)
151 self.assertEqual(isp._is_complete, False)
152
152
153 def test_source(self):
153 def test_source(self):
154 self.isp._store('1')
154 self.isp._store('1')
155 self.isp._store('2')
155 self.isp._store('2')
156 self.assertEqual(self.isp.source, '1\n2\n')
156 self.assertEqual(self.isp.source, '1\n2\n')
157 self.assertTrue(len(self.isp._buffer)>0)
157 self.assertTrue(len(self.isp._buffer)>0)
158 self.assertEqual(self.isp.source_reset(), '1\n2\n')
158 self.assertEqual(self.isp.source_reset(), '1\n2\n')
159 self.assertEqual(self.isp._buffer, [])
159 self.assertEqual(self.isp._buffer, [])
160 self.assertEqual(self.isp.source, '')
160 self.assertEqual(self.isp.source, '')
161
161
162 def test_indent(self):
162 def test_indent(self):
163 isp = self.isp # shorthand
163 isp = self.isp # shorthand
164 isp.push('x=1')
164 isp.push('x=1')
165 self.assertEqual(isp.indent_spaces, 0)
165 self.assertEqual(isp.indent_spaces, 0)
166 isp.push('if 1:\n x=1')
166 isp.push('if 1:\n x=1')
167 self.assertEqual(isp.indent_spaces, 4)
167 self.assertEqual(isp.indent_spaces, 4)
168 isp.push('y=2\n')
168 isp.push('y=2\n')
169 self.assertEqual(isp.indent_spaces, 0)
169 self.assertEqual(isp.indent_spaces, 0)
170
170
171 def test_indent2(self):
171 def test_indent2(self):
172 # In cell mode, inputs must be fed in whole blocks, so skip this test
172 # In cell mode, inputs must be fed in whole blocks, so skip this test
173 if self.isp.input_mode == 'cell': return
173 if self.isp.input_mode == 'cell': return
174
174
175 isp = self.isp
175 isp = self.isp
176 isp.push('if 1:')
176 isp.push('if 1:')
177 self.assertEqual(isp.indent_spaces, 4)
177 self.assertEqual(isp.indent_spaces, 4)
178 isp.push(' x=1')
178 isp.push(' x=1')
179 self.assertEqual(isp.indent_spaces, 4)
179 self.assertEqual(isp.indent_spaces, 4)
180 # Blank lines shouldn't change the indent level
180 # Blank lines shouldn't change the indent level
181 isp.push(' '*2)
181 isp.push(' '*2)
182 self.assertEqual(isp.indent_spaces, 4)
182 self.assertEqual(isp.indent_spaces, 4)
183
183
184 def test_indent3(self):
184 def test_indent3(self):
185 # In cell mode, inputs must be fed in whole blocks, so skip this test
185 # In cell mode, inputs must be fed in whole blocks, so skip this test
186 if self.isp.input_mode == 'cell': return
186 if self.isp.input_mode == 'cell': return
187
187
188 isp = self.isp
188 isp = self.isp
189 # When a multiline statement contains parens or multiline strings, we
189 # When a multiline statement contains parens or multiline strings, we
190 # shouldn't get confused.
190 # shouldn't get confused.
191 isp.push("if 1:")
191 isp.push("if 1:")
192 isp.push(" x = (1+\n 2)")
192 isp.push(" x = (1+\n 2)")
193 self.assertEqual(isp.indent_spaces, 4)
193 self.assertEqual(isp.indent_spaces, 4)
194
194
195 def test_dedent(self):
195 def test_dedent(self):
196 isp = self.isp # shorthand
196 isp = self.isp # shorthand
197 isp.push('if 1:')
197 isp.push('if 1:')
198 self.assertEqual(isp.indent_spaces, 4)
198 self.assertEqual(isp.indent_spaces, 4)
199 isp.push(' pass')
199 isp.push(' pass')
200 self.assertEqual(isp.indent_spaces, 0)
200 self.assertEqual(isp.indent_spaces, 0)
201
201
202 def test_push(self):
202 def test_push(self):
203 isp = self.isp
203 isp = self.isp
204 self.assertTrue(isp.push('x=1'))
204 self.assertTrue(isp.push('x=1'))
205
205
206 def test_push2(self):
206 def test_push2(self):
207 isp = self.isp
207 isp = self.isp
208 self.assertFalse(isp.push('if 1:'))
208 self.assertFalse(isp.push('if 1:'))
209 for line in [' x=1', '# a comment', ' y=2']:
209 for line in [' x=1', '# a comment', ' y=2']:
210 self.assertTrue(isp.push(line))
210 self.assertTrue(isp.push(line))
211
211
212 def test_replace_mode(self):
212 def test_replace_mode(self):
213 isp = self.isp
213 isp = self.isp
214 isp.input_mode = 'cell'
214 isp.input_mode = 'cell'
215 isp.push('x=1')
215 isp.push('x=1')
216 self.assertEqual(isp.source, 'x=1\n')
216 self.assertEqual(isp.source, 'x=1\n')
217 isp.push('x=2')
217 isp.push('x=2')
218 self.assertEqual(isp.source, 'x=2\n')
218 self.assertEqual(isp.source, 'x=2\n')
219
219
220 def test_push_accepts_more(self):
220 def test_push_accepts_more(self):
221 isp = self.isp
221 isp = self.isp
222 isp.push('x=1')
222 isp.push('x=1')
223 self.assertFalse(isp.push_accepts_more())
223 self.assertFalse(isp.push_accepts_more())
224
224
225 def test_push_accepts_more2(self):
225 def test_push_accepts_more2(self):
226 # In cell mode, inputs must be fed in whole blocks, so skip this test
226 # In cell mode, inputs must be fed in whole blocks, so skip this test
227 if self.isp.input_mode == 'cell': return
227 if self.isp.input_mode == 'cell': return
228
228
229 isp = self.isp
229 isp = self.isp
230 isp.push('if 1:')
230 isp.push('if 1:')
231 self.assertTrue(isp.push_accepts_more())
231 self.assertTrue(isp.push_accepts_more())
232 isp.push(' x=1')
232 isp.push(' x=1')
233 self.assertTrue(isp.push_accepts_more())
233 self.assertTrue(isp.push_accepts_more())
234 isp.push('')
234 isp.push('')
235 self.assertFalse(isp.push_accepts_more())
235 self.assertFalse(isp.push_accepts_more())
236
236
237 def test_push_accepts_more3(self):
237 def test_push_accepts_more3(self):
238 isp = self.isp
238 isp = self.isp
239 isp.push("x = (2+\n3)")
239 isp.push("x = (2+\n3)")
240 self.assertFalse(isp.push_accepts_more())
240 self.assertFalse(isp.push_accepts_more())
241
241
242 def test_push_accepts_more4(self):
242 def test_push_accepts_more4(self):
243 # In cell mode, inputs must be fed in whole blocks, so skip this test
243 # In cell mode, inputs must be fed in whole blocks, so skip this test
244 if self.isp.input_mode == 'cell': return
244 if self.isp.input_mode == 'cell': return
245
245
246 isp = self.isp
246 isp = self.isp
247 # When a multiline statement contains parens or multiline strings, we
247 # When a multiline statement contains parens or multiline strings, we
248 # shouldn't get confused.
248 # shouldn't get confused.
249 # FIXME: we should be able to better handle de-dents in statements like
249 # FIXME: we should be able to better handle de-dents in statements like
250 # multiline strings and multiline expressions (continued with \ or
250 # multiline strings and multiline expressions (continued with \ or
251 # parens). Right now we aren't handling the indentation tracking quite
251 # parens). Right now we aren't handling the indentation tracking quite
252 # correctly with this, though in practice it may not be too much of a
252 # correctly with this, though in practice it may not be too much of a
253 # problem. We'll need to see.
253 # problem. We'll need to see.
254 isp.push("if 1:")
254 isp.push("if 1:")
255 isp.push(" x = (2+")
255 isp.push(" x = (2+")
256 isp.push(" 3)")
256 isp.push(" 3)")
257 self.assertTrue(isp.push_accepts_more())
257 self.assertTrue(isp.push_accepts_more())
258 isp.push(" y = 3")
258 isp.push(" y = 3")
259 self.assertTrue(isp.push_accepts_more())
259 self.assertTrue(isp.push_accepts_more())
260 isp.push('')
260 isp.push('')
261 self.assertFalse(isp.push_accepts_more())
261 self.assertFalse(isp.push_accepts_more())
262
262
263 def test_push_accepts_more5(self):
263 def test_push_accepts_more5(self):
264 # In cell mode, inputs must be fed in whole blocks, so skip this test
264 # In cell mode, inputs must be fed in whole blocks, so skip this test
265 if self.isp.input_mode == 'cell': return
265 if self.isp.input_mode == 'cell': return
266
266
267 isp = self.isp
267 isp = self.isp
268 isp.push('try:')
268 isp.push('try:')
269 isp.push(' a = 5')
269 isp.push(' a = 5')
270 isp.push('except:')
270 isp.push('except:')
271 isp.push(' raise')
271 isp.push(' raise')
272 self.assertTrue(isp.push_accepts_more())
272 self.assertTrue(isp.push_accepts_more())
273
273
274 def test_continuation(self):
274 def test_continuation(self):
275 isp = self.isp
275 isp = self.isp
276 isp.push("import os, \\")
276 isp.push("import os, \\")
277 self.assertTrue(isp.push_accepts_more())
277 self.assertTrue(isp.push_accepts_more())
278 isp.push("sys")
278 isp.push("sys")
279 self.assertFalse(isp.push_accepts_more())
279 self.assertFalse(isp.push_accepts_more())
280
280
281 def test_syntax_error(self):
281 def test_syntax_error(self):
282 isp = self.isp
282 isp = self.isp
283 # Syntax errors immediately produce a 'ready' block, so the invalid
283 # Syntax errors immediately produce a 'ready' block, so the invalid
284 # Python can be sent to the kernel for evaluation with possible ipython
284 # Python can be sent to the kernel for evaluation with possible ipython
285 # special-syntax conversion.
285 # special-syntax conversion.
286 isp.push('run foo')
286 isp.push('run foo')
287 self.assertFalse(isp.push_accepts_more())
287 self.assertFalse(isp.push_accepts_more())
288
288
289 def check_split(self, block_lines, compile=True):
289 def check_split(self, block_lines, compile=True):
290 blocks = assemble(block_lines)
290 blocks = assemble(block_lines)
291 lines = ''.join(blocks)
291 lines = ''.join(blocks)
292 oblock = self.isp.split_blocks(lines)
292 oblock = self.isp.split_blocks(lines)
293 self.assertEqual(oblock, blocks)
293 self.assertEqual(oblock, blocks)
294 if compile:
294 if compile:
295 for block in blocks:
295 for block in blocks:
296 self.isp._compile(block)
296 self.isp._compile(block)
297
297
298 def test_split(self):
298 def test_split(self):
299 # All blocks of input we want to test in a list. The format for each
299 # All blocks of input we want to test in a list. The format for each
300 # block is a list of lists, with each inner lists consisting of all the
300 # block is a list of lists, with each inner lists consisting of all the
301 # lines (as single-lines) that should make up a sub-block.
301 # lines (as single-lines) that should make up a sub-block.
302
302
303 # Note: do NOT put here sub-blocks that don't compile, as the
303 # Note: do NOT put here sub-blocks that don't compile, as the
304 # check_split() routine makes a final verification pass to check that
304 # check_split() routine makes a final verification pass to check that
305 # each sub_block, as returned by split_blocks(), does compile
305 # each sub_block, as returned by split_blocks(), does compile
306 # correctly.
306 # correctly.
307 all_blocks = [ [['x=1']],
307 all_blocks = [ [['x=1']],
308
308
309 [['x=1'],
309 [['x=1'],
310 ['y=2']],
310 ['y=2']],
311
311
312 [['x=1',
312 [['x=1',
313 '# a comment'],
313 '# a comment'],
314 ['y=11']],
314 ['y=11']],
315
315
316 [['if 1:',
316 [['if 1:',
317 ' x=1'],
317 ' x=1'],
318 ['y=3']],
318 ['y=3']],
319
319
320 [['def f(x):',
320 [['def f(x):',
321 ' return x'],
321 ' return x'],
322 ['x=1']],
322 ['x=1']],
323
323
324 [['def f(x):',
324 [['def f(x):',
325 ' x+=1',
325 ' x+=1',
326 ' ',
326 ' ',
327 ' return x'],
327 ' return x'],
328 ['x=1']],
328 ['x=1']],
329
329
330 [['def f(x):',
330 [['def f(x):',
331 ' if x>0:',
331 ' if x>0:',
332 ' y=1',
332 ' y=1',
333 ' # a comment',
333 ' # a comment',
334 ' else:',
334 ' else:',
335 ' y=4',
335 ' y=4',
336 ' ',
336 ' ',
337 ' return y'],
337 ' return y'],
338 ['x=1'],
338 ['x=1'],
339 ['if 1:',
339 ['if 1:',
340 ' y=11'] ],
340 ' y=11'] ],
341
341
342 [['for i in range(10):'
342 [['for i in range(10):'
343 ' x=i**2']],
343 ' x=i**2']],
344
344
345 [['for i in range(10):'
345 [['for i in range(10):'
346 ' x=i**2'],
346 ' x=i**2'],
347 ['z = 1']],
347 ['z = 1']],
348
348
349 [['"asdf"']],
349 [['"asdf"']],
350
350
351 [['"asdf"'],
351 [['"asdf"'],
352 ['10'],
352 ['10'],
353 ],
353 ],
354
354
355 [['"""foo',
355 [['"""foo',
356 'bar"""']],
356 'bar"""']],
357 ]
357 ]
358 for block_lines in all_blocks:
358 for block_lines in all_blocks:
359 self.check_split(block_lines)
359 self.check_split(block_lines)
360
360
361 def test_split_syntax_errors(self):
361 def test_split_syntax_errors(self):
362 # Block splitting with invalid syntax
362 # Block splitting with invalid syntax
363 all_blocks = [ [['a syntax error']],
363 all_blocks = [ [['a syntax error']],
364
364
365 [['x=1',
365 [['x=1',
366 'another syntax error']],
366 'another syntax error']],
367
367
368 [['for i in range(10):'
368 [['for i in range(10):'
369 ' yet another error']],
369 ' yet another error']],
370
370
371 ]
371 ]
372 for block_lines in all_blocks:
372 for block_lines in all_blocks:
373 self.check_split(block_lines, compile=False)
373 self.check_split(block_lines, compile=False)
374
374
375 def test_unicode(self):
375 def test_unicode(self):
376 self.isp.push(u"PΓ©rez")
376 self.isp.push(u"PΓ©rez")
377 self.isp.push(u'\xc3\xa9')
377 self.isp.push(u'\xc3\xa9')
378 self.isp.push(u"u'\xc3\xa9'")
378 self.isp.push(u"u'\xc3\xa9'")
379
379
380 class InteractiveLoopTestCase(unittest.TestCase):
380 class InteractiveLoopTestCase(unittest.TestCase):
381 """Tests for an interactive loop like a python shell.
381 """Tests for an interactive loop like a python shell.
382 """
382 """
383 def check_ns(self, lines, ns):
383 def check_ns(self, lines, ns):
384 """Validate that the given input lines produce the resulting namespace.
384 """Validate that the given input lines produce the resulting namespace.
385
385
386 Note: the input lines are given exactly as they would be typed in an
386 Note: the input lines are given exactly as they would be typed in an
387 auto-indenting environment, as mini_interactive_loop above already does
387 auto-indenting environment, as mini_interactive_loop above already does
388 auto-indenting and prepends spaces to the input.
388 auto-indenting and prepends spaces to the input.
389 """
389 """
390 src = mini_interactive_loop(pseudo_input(lines))
390 src = mini_interactive_loop(pseudo_input(lines))
391 test_ns = {}
391 test_ns = {}
392 exec src in test_ns
392 exec src in test_ns
393 # We can't check that the provided ns is identical to the test_ns,
393 # We can't check that the provided ns is identical to the test_ns,
394 # because Python fills test_ns with extra keys (copyright, etc). But
394 # because Python fills test_ns with extra keys (copyright, etc). But
395 # we can check that the given dict is *contained* in test_ns
395 # we can check that the given dict is *contained* in test_ns
396 for k,v in ns.iteritems():
396 for k,v in ns.iteritems():
397 self.assertEqual(test_ns[k], v)
397 self.assertEqual(test_ns[k], v)
398
398
399 def test_simple(self):
399 def test_simple(self):
400 self.check_ns(['x=1'], dict(x=1))
400 self.check_ns(['x=1'], dict(x=1))
401
401
402 def test_simple2(self):
402 def test_simple2(self):
403 self.check_ns(['if 1:', 'x=2'], dict(x=2))
403 self.check_ns(['if 1:', 'x=2'], dict(x=2))
404
404
405 def test_xy(self):
405 def test_xy(self):
406 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
406 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
407
407
408 def test_abc(self):
408 def test_abc(self):
409 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
409 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
410
410
411 def test_multi(self):
411 def test_multi(self):
412 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
412 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
413
413
414
414
415 def test_LineInfo():
415 def test_LineInfo():
416 """Simple test for LineInfo construction and str()"""
416 """Simple test for LineInfo construction and str()"""
417 linfo = isp.LineInfo(' %cd /home')
417 linfo = isp.LineInfo(' %cd /home')
418 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
418 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
419
419
420
420
421 def test_split_user_input():
421 def test_split_user_input():
422 """Unicode test - split_user_input already has good doctests"""
422 """Unicode test - split_user_input already has good doctests"""
423 line = u"PΓ©rez Fernando"
423 line = u"PΓ©rez Fernando"
424 parts = isp.split_user_input(line)
424 parts = isp.split_user_input(line)
425 parts_expected = (u'', u'', u'', line)
425 parts_expected = (u'', u'', u'', line)
426 nt.assert_equal(parts, parts_expected)
426 nt.assert_equal(parts, parts_expected)
427
427
428
428
429 # Transformer tests
429 # Transformer tests
430 def transform_checker(tests, func):
430 def transform_checker(tests, func):
431 """Utility to loop over test inputs"""
431 """Utility to loop over test inputs"""
432 for inp, tr in tests:
432 for inp, tr in tests:
433 nt.assert_equals(func(inp), tr)
433 nt.assert_equals(func(inp), tr)
434
434
435 # Data for all the syntax tests in the form of lists of pairs of
435 # Data for all the syntax tests in the form of lists of pairs of
436 # raw/transformed input. We store it here as a global dict so that we can use
436 # raw/transformed input. We store it here as a global dict so that we can use
437 # it both within single-function tests and also to validate the behavior of the
437 # it both within single-function tests and also to validate the behavior of the
438 # larger objects
438 # larger objects
439
439
440 syntax = \
440 syntax = \
441 dict(assign_system =
441 dict(assign_system =
442 [('a =! ls', 'a = get_ipython().getoutput("ls")'),
442 [('a =! ls', 'a = get_ipython().getoutput(u"ls")'),
443 ('b = !ls', 'b = get_ipython().getoutput("ls")'),
443 ('b = !ls', 'b = get_ipython().getoutput(u"ls")'),
444 ('x=1', 'x=1'), # normal input is unmodified
444 ('x=1', 'x=1'), # normal input is unmodified
445 (' ',' '), # blank lines are kept intact
445 (' ',' '), # blank lines are kept intact
446 ],
446 ],
447
447
448 assign_magic =
448 assign_magic =
449 [('a =% who', 'a = get_ipython().magic("who")'),
449 [('a =% who', 'a = get_ipython().magic(u"who")'),
450 ('b = %who', 'b = get_ipython().magic("who")'),
450 ('b = %who', 'b = get_ipython().magic(u"who")'),
451 ('x=1', 'x=1'), # normal input is unmodified
451 ('x=1', 'x=1'), # normal input is unmodified
452 (' ',' '), # blank lines are kept intact
452 (' ',' '), # blank lines are kept intact
453 ],
453 ],
454
454
455 classic_prompt =
455 classic_prompt =
456 [('>>> x=1', 'x=1'),
456 [('>>> x=1', 'x=1'),
457 ('x=1', 'x=1'), # normal input is unmodified
457 ('x=1', 'x=1'), # normal input is unmodified
458 (' ', ' '), # blank lines are kept intact
458 (' ', ' '), # blank lines are kept intact
459 ('... ', ''), # continuation prompts
459 ('... ', ''), # continuation prompts
460 ],
460 ],
461
461
462 ipy_prompt =
462 ipy_prompt =
463 [('In [1]: x=1', 'x=1'),
463 [('In [1]: x=1', 'x=1'),
464 ('x=1', 'x=1'), # normal input is unmodified
464 ('x=1', 'x=1'), # normal input is unmodified
465 (' ',' '), # blank lines are kept intact
465 (' ',' '), # blank lines are kept intact
466 (' ....: ', ''), # continuation prompts
466 (' ....: ', ''), # continuation prompts
467 ],
467 ],
468
468
469 # Tests for the escape transformer to leave normal code alone
469 # Tests for the escape transformer to leave normal code alone
470 escaped_noesc =
470 escaped_noesc =
471 [ (' ', ' '),
471 [ (' ', ' '),
472 ('x=1', 'x=1'),
472 ('x=1', 'x=1'),
473 ],
473 ],
474
474
475 # System calls
475 # System calls
476 escaped_shell =
476 escaped_shell =
477 [ ('!ls', 'get_ipython().system("ls")'),
477 [ ('!ls', 'get_ipython().system(u"ls")'),
478 # Double-escape shell, this means to capture the output of the
478 # Double-escape shell, this means to capture the output of the
479 # subprocess and return it
479 # subprocess and return it
480 ('!!ls', 'get_ipython().getoutput("ls")'),
480 ('!!ls', 'get_ipython().getoutput(u"ls")'),
481 ],
481 ],
482
482
483 # Help/object info
483 # Help/object info
484 escaped_help =
484 escaped_help =
485 [ ('?', 'get_ipython().show_usage()'),
485 [ ('?', 'get_ipython().show_usage()'),
486 ('?x1', 'get_ipython().magic("pinfo x1")'),
486 ('?x1', 'get_ipython().magic(u"pinfo x1")'),
487 ('??x2', 'get_ipython().magic("pinfo2 x2")'),
487 ('??x2', 'get_ipython().magic(u"pinfo2 x2")'),
488 ('x3?', 'get_ipython().magic("pinfo x3")'),
488 ('x3?', 'get_ipython().magic(u"pinfo x3")'),
489 ('x4??', 'get_ipython().magic("pinfo2 x4")'),
489 ('x4??', 'get_ipython().magic(u"pinfo2 x4")'),
490 ('%hist?', 'get_ipython().magic("pinfo %hist")'),
490 ('%hist?', 'get_ipython().magic(u"pinfo %hist")'),
491 ('f*?', 'get_ipython().magic("psearch f*")'),
491 ('f*?', 'get_ipython().magic(u"psearch f*")'),
492 ('ax.*aspe*?', 'get_ipython().magic("psearch ax.*aspe*")'),
492 ('ax.*aspe*?', 'get_ipython().magic(u"psearch ax.*aspe*")'),
493 ],
493 ],
494
494
495 # Explicit magic calls
495 # Explicit magic calls
496 escaped_magic =
496 escaped_magic =
497 [ ('%cd', 'get_ipython().magic("cd")'),
497 [ ('%cd', 'get_ipython().magic(u"cd")'),
498 ('%cd /home', 'get_ipython().magic("cd /home")'),
498 ('%cd /home', 'get_ipython().magic(u"cd /home")'),
499 (' %magic', ' get_ipython().magic("magic")'),
499 (' %magic', ' get_ipython().magic(u"magic")'),
500 ],
500 ],
501
501
502 # Quoting with separate arguments
502 # Quoting with separate arguments
503 escaped_quote =
503 escaped_quote =
504 [ (',f', 'f("")'),
504 [ (',f', 'f("")'),
505 (',f x', 'f("x")'),
505 (',f x', 'f("x")'),
506 (' ,f y', ' f("y")'),
506 (' ,f y', ' f("y")'),
507 (',f a b', 'f("a", "b")'),
507 (',f a b', 'f("a", "b")'),
508 ],
508 ],
509
509
510 # Quoting with single argument
510 # Quoting with single argument
511 escaped_quote2 =
511 escaped_quote2 =
512 [ (';f', 'f("")'),
512 [ (';f', 'f("")'),
513 (';f x', 'f("x")'),
513 (';f x', 'f("x")'),
514 (' ;f y', ' f("y")'),
514 (' ;f y', ' f("y")'),
515 (';f a b', 'f("a b")'),
515 (';f a b', 'f("a b")'),
516 ],
516 ],
517
517
518 # Simply apply parens
518 # Simply apply parens
519 escaped_paren =
519 escaped_paren =
520 [ ('/f', 'f()'),
520 [ ('/f', 'f()'),
521 ('/f x', 'f(x)'),
521 ('/f x', 'f(x)'),
522 (' /f y', ' f(y)'),
522 (' /f y', ' f(y)'),
523 ('/f a b', 'f(a, b)'),
523 ('/f a b', 'f(a, b)'),
524 ],
524 ],
525
525
526 )
526 )
527
527
528 # multiline syntax examples. Each of these should be a list of lists, with
528 # multiline syntax examples. Each of these should be a list of lists, with
529 # each entry itself having pairs of raw/transformed input. The union (with
529 # each entry itself having pairs of raw/transformed input. The union (with
530 # '\n'.join() of the transformed inputs is what the splitter should produce
530 # '\n'.join() of the transformed inputs is what the splitter should produce
531 # when fed the raw lines one at a time via push.
531 # when fed the raw lines one at a time via push.
532 syntax_ml = \
532 syntax_ml = \
533 dict(classic_prompt =
533 dict(classic_prompt =
534 [ [('>>> for i in range(10):','for i in range(10):'),
534 [ [('>>> for i in range(10):','for i in range(10):'),
535 ('... print i',' print i'),
535 ('... print i',' print i'),
536 ('... ', ''),
536 ('... ', ''),
537 ],
537 ],
538 ],
538 ],
539
539
540 ipy_prompt =
540 ipy_prompt =
541 [ [('In [24]: for i in range(10):','for i in range(10):'),
541 [ [('In [24]: for i in range(10):','for i in range(10):'),
542 (' ....: print i',' print i'),
542 (' ....: print i',' print i'),
543 (' ....: ', ''),
543 (' ....: ', ''),
544 ],
544 ],
545 ],
545 ],
546 )
546 )
547
547
548
548
549 def test_assign_system():
549 def test_assign_system():
550 transform_checker(syntax['assign_system'], isp.transform_assign_system)
550 transform_checker(syntax['assign_system'], isp.transform_assign_system)
551
551
552
552
553 def test_assign_magic():
553 def test_assign_magic():
554 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
554 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
555
555
556
556
557 def test_classic_prompt():
557 def test_classic_prompt():
558 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
558 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
559 for example in syntax_ml['classic_prompt']:
559 for example in syntax_ml['classic_prompt']:
560 transform_checker(example, isp.transform_classic_prompt)
560 transform_checker(example, isp.transform_classic_prompt)
561
561
562
562
563 def test_ipy_prompt():
563 def test_ipy_prompt():
564 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
564 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
565 for example in syntax_ml['ipy_prompt']:
565 for example in syntax_ml['ipy_prompt']:
566 transform_checker(example, isp.transform_ipy_prompt)
566 transform_checker(example, isp.transform_ipy_prompt)
567
567
568
568
569 def test_escaped_noesc():
569 def test_escaped_noesc():
570 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
570 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
571
571
572
572
573 def test_escaped_shell():
573 def test_escaped_shell():
574 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
574 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
575
575
576
576
577 def test_escaped_help():
577 def test_escaped_help():
578 transform_checker(syntax['escaped_help'], isp.transform_escaped)
578 transform_checker(syntax['escaped_help'], isp.transform_escaped)
579
579
580
580
581 def test_escaped_magic():
581 def test_escaped_magic():
582 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
582 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
583
583
584
584
585 def test_escaped_quote():
585 def test_escaped_quote():
586 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
586 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
587
587
588
588
589 def test_escaped_quote2():
589 def test_escaped_quote2():
590 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
590 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
591
591
592
592
593 def test_escaped_paren():
593 def test_escaped_paren():
594 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
594 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
595
595
596
596
597 class IPythonInputTestCase(InputSplitterTestCase):
597 class IPythonInputTestCase(InputSplitterTestCase):
598 """By just creating a new class whose .isp is a different instance, we
598 """By just creating a new class whose .isp is a different instance, we
599 re-run the same test battery on the new input splitter.
599 re-run the same test battery on the new input splitter.
600
600
601 In addition, this runs the tests over the syntax and syntax_ml dicts that
601 In addition, this runs the tests over the syntax and syntax_ml dicts that
602 were tested by individual functions, as part of the OO interface.
602 were tested by individual functions, as part of the OO interface.
603
603
604 It also makes some checks on the raw buffer storage.
604 It also makes some checks on the raw buffer storage.
605 """
605 """
606
606
607 def setUp(self):
607 def setUp(self):
608 self.isp = isp.IPythonInputSplitter(input_mode='line')
608 self.isp = isp.IPythonInputSplitter(input_mode='line')
609
609
610 def test_syntax(self):
610 def test_syntax(self):
611 """Call all single-line syntax tests from the main object"""
611 """Call all single-line syntax tests from the main object"""
612 isp = self.isp
612 isp = self.isp
613 for example in syntax.itervalues():
613 for example in syntax.itervalues():
614 for raw, out_t in example:
614 for raw, out_t in example:
615 if raw.startswith(' '):
615 if raw.startswith(' '):
616 continue
616 continue
617
617
618 isp.push(raw)
618 isp.push(raw)
619 out, out_raw = isp.source_raw_reset()
619 out, out_raw = isp.source_raw_reset()
620 self.assertEqual(out.rstrip(), out_t)
620 self.assertEqual(out.rstrip(), out_t)
621 self.assertEqual(out_raw.rstrip(), raw.rstrip())
621 self.assertEqual(out_raw.rstrip(), raw.rstrip())
622
622
623 def test_syntax_multiline(self):
623 def test_syntax_multiline(self):
624 isp = self.isp
624 isp = self.isp
625 for example in syntax_ml.itervalues():
625 for example in syntax_ml.itervalues():
626 out_t_parts = []
626 out_t_parts = []
627 raw_parts = []
627 raw_parts = []
628 for line_pairs in example:
628 for line_pairs in example:
629 for lraw, out_t_part in line_pairs:
629 for lraw, out_t_part in line_pairs:
630 isp.push(lraw)
630 isp.push(lraw)
631 out_t_parts.append(out_t_part)
631 out_t_parts.append(out_t_part)
632 raw_parts.append(lraw)
632 raw_parts.append(lraw)
633
633
634 out, out_raw = isp.source_raw_reset()
634 out, out_raw = isp.source_raw_reset()
635 out_t = '\n'.join(out_t_parts).rstrip()
635 out_t = '\n'.join(out_t_parts).rstrip()
636 raw = '\n'.join(raw_parts).rstrip()
636 raw = '\n'.join(raw_parts).rstrip()
637 self.assertEqual(out.rstrip(), out_t)
637 self.assertEqual(out.rstrip(), out_t)
638 self.assertEqual(out_raw.rstrip(), raw)
638 self.assertEqual(out_raw.rstrip(), raw)
639
639
640
640
641 class BlockIPythonInputTestCase(IPythonInputTestCase):
641 class BlockIPythonInputTestCase(IPythonInputTestCase):
642
642
643 # Deactivate tests that don't make sense for the block mode
643 # Deactivate tests that don't make sense for the block mode
644 test_push3 = test_split = lambda s: None
644 test_push3 = test_split = lambda s: None
645
645
646 def setUp(self):
646 def setUp(self):
647 self.isp = isp.IPythonInputSplitter(input_mode='cell')
647 self.isp = isp.IPythonInputSplitter(input_mode='cell')
648
648
649 def test_syntax_multiline(self):
649 def test_syntax_multiline(self):
650 isp = self.isp
650 isp = self.isp
651 for example in syntax_ml.itervalues():
651 for example in syntax_ml.itervalues():
652 raw_parts = []
652 raw_parts = []
653 out_t_parts = []
653 out_t_parts = []
654 for line_pairs in example:
654 for line_pairs in example:
655 for raw, out_t_part in line_pairs:
655 for raw, out_t_part in line_pairs:
656 raw_parts.append(raw)
656 raw_parts.append(raw)
657 out_t_parts.append(out_t_part)
657 out_t_parts.append(out_t_part)
658
658
659 raw = '\n'.join(raw_parts)
659 raw = '\n'.join(raw_parts)
660 out_t = '\n'.join(out_t_parts)
660 out_t = '\n'.join(out_t_parts)
661
661
662 isp.push(raw)
662 isp.push(raw)
663 out, out_raw = isp.source_raw_reset()
663 out, out_raw = isp.source_raw_reset()
664 # Match ignoring trailing whitespace
664 # Match ignoring trailing whitespace
665 self.assertEqual(out.rstrip(), out_t.rstrip())
665 self.assertEqual(out.rstrip(), out_t.rstrip())
666 self.assertEqual(out_raw.rstrip(), raw.rstrip())
666 self.assertEqual(out_raw.rstrip(), raw.rstrip())
667
667
668
668
669 #-----------------------------------------------------------------------------
669 #-----------------------------------------------------------------------------
670 # Main - use as a script, mostly for developer experiments
670 # Main - use as a script, mostly for developer experiments
671 #-----------------------------------------------------------------------------
671 #-----------------------------------------------------------------------------
672
672
673 if __name__ == '__main__':
673 if __name__ == '__main__':
674 # A simple demo for interactive experimentation. This code will not get
674 # A simple demo for interactive experimentation. This code will not get
675 # picked up by any test suite.
675 # picked up by any test suite.
676 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
676 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
677
677
678 # configure here the syntax to use, prompt and whether to autoindent
678 # configure here the syntax to use, prompt and whether to autoindent
679 #isp, start_prompt = InputSplitter(), '>>> '
679 #isp, start_prompt = InputSplitter(), '>>> '
680 isp, start_prompt = IPythonInputSplitter(), 'In> '
680 isp, start_prompt = IPythonInputSplitter(), 'In> '
681
681
682 autoindent = True
682 autoindent = True
683 #autoindent = False
683 #autoindent = False
684
684
685 try:
685 try:
686 while True:
686 while True:
687 prompt = start_prompt
687 prompt = start_prompt
688 while isp.push_accepts_more():
688 while isp.push_accepts_more():
689 indent = ' '*isp.indent_spaces
689 indent = ' '*isp.indent_spaces
690 if autoindent:
690 if autoindent:
691 line = indent + raw_input(prompt+indent)
691 line = indent + raw_input(prompt+indent)
692 else:
692 else:
693 line = raw_input(prompt)
693 line = raw_input(prompt)
694 isp.push(line)
694 isp.push(line)
695 prompt = '... '
695 prompt = '... '
696
696
697 # Here we just return input so we can use it in a test suite, but a
697 # Here we just return input so we can use it in a test suite, but a
698 # real interpreter would instead send it for execution somewhere.
698 # real interpreter would instead send it for execution somewhere.
699 #src = isp.source; raise EOFError # dbg
699 #src = isp.source; raise EOFError # dbg
700 src, raw = isp.source_raw_reset()
700 src, raw = isp.source_raw_reset()
701 print 'Input source was:\n', src
701 print 'Input source was:\n', src
702 print 'Raw source was:\n', raw
702 print 'Raw source was:\n', raw
703 except EOFError:
703 except EOFError:
704 print 'Bye'
704 print 'Bye'
@@ -1,271 +1,271 b''
1 """Tests for the key interactiveshell module, where the main ipython class is defined.
1 """Tests for the key interactiveshell module, where the main ipython class is defined.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Module imports
4 # Module imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 # stdlib
7 # stdlib
8 import os
8 import os
9 import shutil
9 import shutil
10 import tempfile
10 import tempfile
11
11
12 # third party
12 # third party
13 import nose.tools as nt
13 import nose.tools as nt
14
14
15 # our own packages
15 # our own packages
16 from IPython.testing import decorators as dec
16 from IPython.testing import decorators as dec
17 from IPython.testing.globalipapp import get_ipython
17 from IPython.testing.globalipapp import get_ipython
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Globals
20 # Globals
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 # Get the public instance of IPython
23 # Get the public instance of IPython
24 ip = get_ipython()
24 ip = get_ipython()
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Test functions
27 # Test functions
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 @dec.parametric
30 @dec.parametric
31 def test_reset():
31 def test_reset():
32 """reset must clear most namespaces."""
32 """reset must clear most namespaces."""
33 # The number of variables in the private user_ns_hidden is not zero, but it
33 # The number of variables in the private user_ns_hidden is not zero, but it
34 # should be constant regardless of what we do
34 # should be constant regardless of what we do
35 nvars_config_ns = len(ip.user_ns_hidden)
35 nvars_config_ns = len(ip.user_ns_hidden)
36
36
37 # Check that reset runs without error
37 # Check that reset runs without error
38 ip.reset()
38 ip.reset()
39
39
40 # Once we've reset it (to clear of any junk that might have been there from
40 # Once we've reset it (to clear of any junk that might have been there from
41 # other tests, we can count how many variables are in the user's namespace
41 # other tests, we can count how many variables are in the user's namespace
42 nvars_user_ns = len(ip.user_ns)
42 nvars_user_ns = len(ip.user_ns)
43
43
44 # Now add a few variables to user_ns, and check that reset clears them
44 # Now add a few variables to user_ns, and check that reset clears them
45 ip.user_ns['x'] = 1
45 ip.user_ns['x'] = 1
46 ip.user_ns['y'] = 1
46 ip.user_ns['y'] = 1
47 ip.reset()
47 ip.reset()
48
48
49 # Finally, check that all namespaces have only as many variables as we
49 # Finally, check that all namespaces have only as many variables as we
50 # expect to find in them:
50 # expect to find in them:
51 for ns in ip.ns_refs_table:
51 for ns in ip.ns_refs_table:
52 if ns is ip.user_ns:
52 if ns is ip.user_ns:
53 nvars_expected = nvars_user_ns
53 nvars_expected = nvars_user_ns
54 elif ns is ip.user_ns_hidden:
54 elif ns is ip.user_ns_hidden:
55 nvars_expected = nvars_config_ns
55 nvars_expected = nvars_config_ns
56 else:
56 else:
57 nvars_expected = 0
57 nvars_expected = 0
58
58
59 yield nt.assert_equals(len(ns), nvars_expected)
59 yield nt.assert_equals(len(ns), nvars_expected)
60
60
61
61
62 # Tests for reporting of exceptions in various modes, handling of SystemExit,
62 # Tests for reporting of exceptions in various modes, handling of SystemExit,
63 # and %tb functionality. This is really a mix of testing ultraTB and interactiveshell.
63 # and %tb functionality. This is really a mix of testing ultraTB and interactiveshell.
64
64
65 def doctest_tb_plain():
65 def doctest_tb_plain():
66 """
66 """
67 In [18]: xmode plain
67 In [18]: xmode plain
68 Exception reporting mode: Plain
68 Exception reporting mode: Plain
69
69
70 In [19]: run simpleerr.py
70 In [19]: run simpleerr.py
71 Traceback (most recent call last):
71 Traceback (most recent call last):
72 ...line 32, in <module>
72 ...line 32, in <module>
73 bar(mode)
73 bar(mode)
74 ...line 16, in bar
74 ...line 16, in bar
75 div0()
75 div0()
76 ...line 8, in div0
76 ...line 8, in div0
77 x/y
77 x/y
78 ZeroDivisionError: integer division or modulo by zero
78 ZeroDivisionError: integer division or modulo by zero
79 """
79 """
80
80
81
81
82 def doctest_tb_context():
82 def doctest_tb_context():
83 """
83 """
84 In [3]: xmode context
84 In [3]: xmode context
85 Exception reporting mode: Context
85 Exception reporting mode: Context
86
86
87 In [4]: run simpleerr.py
87 In [4]: run simpleerr.py
88 ---------------------------------------------------------------------------
88 ---------------------------------------------------------------------------
89 ZeroDivisionError Traceback (most recent call last)
89 ZeroDivisionError Traceback (most recent call last)
90 <BLANKLINE>
90 <BLANKLINE>
91 ... in <module>()
91 ... in <module>()
92 30 mode = 'div'
92 30 mode = 'div'
93 31
93 31
94 ---> 32 bar(mode)
94 ---> 32 bar(mode)
95 <BLANKLINE>
95 <BLANKLINE>
96 ... in bar(mode)
96 ... in bar(mode)
97 14 "bar"
97 14 "bar"
98 15 if mode=='div':
98 15 if mode=='div':
99 ---> 16 div0()
99 ---> 16 div0()
100 17 elif mode=='exit':
100 17 elif mode=='exit':
101 18 try:
101 18 try:
102 <BLANKLINE>
102 <BLANKLINE>
103 ... in div0()
103 ... in div0()
104 6 x = 1
104 6 x = 1
105 7 y = 0
105 7 y = 0
106 ----> 8 x/y
106 ----> 8 x/y
107 9
107 9
108 10 def sysexit(stat, mode):
108 10 def sysexit(stat, mode):
109 <BLANKLINE>
109 <BLANKLINE>
110 ZeroDivisionError: integer division or modulo by zero
110 ZeroDivisionError: integer division or modulo by zero
111 """
111 """
112
112
113
113
114 def doctest_tb_verbose():
114 def doctest_tb_verbose():
115 """
115 """
116 In [5]: xmode verbose
116 In [5]: xmode verbose
117 Exception reporting mode: Verbose
117 Exception reporting mode: Verbose
118
118
119 In [6]: run simpleerr.py
119 In [6]: run simpleerr.py
120 ---------------------------------------------------------------------------
120 ---------------------------------------------------------------------------
121 ZeroDivisionError Traceback (most recent call last)
121 ZeroDivisionError Traceback (most recent call last)
122 <BLANKLINE>
122 <BLANKLINE>
123 ... in <module>()
123 ... in <module>()
124 30 mode = 'div'
124 30 mode = 'div'
125 31
125 31
126 ---> 32 bar(mode)
126 ---> 32 bar(mode)
127 global bar = <function bar at ...>
127 global bar = <function bar at ...>
128 global mode = 'div'
128 global mode = 'div'
129 <BLANKLINE>
129 <BLANKLINE>
130 ... in bar(mode='div')
130 ... in bar(mode='div')
131 14 "bar"
131 14 "bar"
132 15 if mode=='div':
132 15 if mode=='div':
133 ---> 16 div0()
133 ---> 16 div0()
134 global div0 = <function div0 at ...>
134 global div0 = <function div0 at ...>
135 17 elif mode=='exit':
135 17 elif mode=='exit':
136 18 try:
136 18 try:
137 <BLANKLINE>
137 <BLANKLINE>
138 ... in div0()
138 ... in div0()
139 6 x = 1
139 6 x = 1
140 7 y = 0
140 7 y = 0
141 ----> 8 x/y
141 ----> 8 x/y
142 x = 1
142 x = 1
143 y = 0
143 y = 0
144 9
144 9
145 10 def sysexit(stat, mode):
145 10 def sysexit(stat, mode):
146 <BLANKLINE>
146 <BLANKLINE>
147 ZeroDivisionError: integer division or modulo by zero
147 ZeroDivisionError: integer division or modulo by zero
148 """
148 """
149
149
150
150
151 def doctest_tb_sysexit():
151 def doctest_tb_sysexit():
152 """
152 """
153 In [17]: %xmode plain
153 In [17]: %xmode plain
154 Exception reporting mode: Plain
154 Exception reporting mode: Plain
155
155
156 In [18]: %run simpleerr.py exit
156 In [18]: %run simpleerr.py exit
157 An exception has occurred, use %tb to see the full traceback.
157 An exception has occurred, use %tb to see the full traceback.
158 SystemExit: (1, 'Mode = exit')
158 SystemExit: (1, u'Mode = exit')
159
159
160 In [19]: %run simpleerr.py exit 2
160 In [19]: %run simpleerr.py exit 2
161 An exception has occurred, use %tb to see the full traceback.
161 An exception has occurred, use %tb to see the full traceback.
162 SystemExit: (2, 'Mode = exit')
162 SystemExit: (2, u'Mode = exit')
163
163
164 In [20]: %tb
164 In [20]: %tb
165 Traceback (most recent call last):
165 Traceback (most recent call last):
166 File ... in <module>
166 File ... in <module>
167 bar(mode)
167 bar(mode)
168 File ... line 22, in bar
168 File ... line 22, in bar
169 sysexit(stat, mode)
169 sysexit(stat, mode)
170 File ... line 11, in sysexit
170 File ... line 11, in sysexit
171 raise SystemExit(stat, 'Mode = %s' % mode)
171 raise SystemExit(stat, 'Mode = %s' % mode)
172 SystemExit: (2, 'Mode = exit')
172 SystemExit: (2, u'Mode = exit')
173
173
174 In [21]: %xmode context
174 In [21]: %xmode context
175 Exception reporting mode: Context
175 Exception reporting mode: Context
176
176
177 In [22]: %tb
177 In [22]: %tb
178 ---------------------------------------------------------------------------
178 ---------------------------------------------------------------------------
179 SystemExit Traceback (most recent call last)
179 SystemExit Traceback (most recent call last)
180 <BLANKLINE>
180 <BLANKLINE>
181 ...<module>()
181 ...<module>()
182 30 mode = 'div'
182 30 mode = 'div'
183 31
183 31
184 ---> 32 bar(mode)
184 ---> 32 bar(mode)
185 <BLANKLINE>
185 <BLANKLINE>
186 ...bar(mode)
186 ...bar(mode)
187 20 except:
187 20 except:
188 21 stat = 1
188 21 stat = 1
189 ---> 22 sysexit(stat, mode)
189 ---> 22 sysexit(stat, mode)
190 23 else:
190 23 else:
191 24 raise ValueError('Unknown mode')
191 24 raise ValueError('Unknown mode')
192 <BLANKLINE>
192 <BLANKLINE>
193 ...sysexit(stat, mode)
193 ...sysexit(stat, mode)
194 9
194 9
195 10 def sysexit(stat, mode):
195 10 def sysexit(stat, mode):
196 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
196 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
197 12
197 12
198 13 def bar(mode):
198 13 def bar(mode):
199 <BLANKLINE>
199 <BLANKLINE>
200 SystemExit: (2, 'Mode = exit')
200 SystemExit: (2, u'Mode = exit')
201
201
202 In [23]: %xmode verbose
202 In [23]: %xmode verbose
203 Exception reporting mode: Verbose
203 Exception reporting mode: Verbose
204
204
205 In [24]: %tb
205 In [24]: %tb
206 ---------------------------------------------------------------------------
206 ---------------------------------------------------------------------------
207 SystemExit Traceback (most recent call last)
207 SystemExit Traceback (most recent call last)
208 <BLANKLINE>
208 <BLANKLINE>
209 ... in <module>()
209 ... in <module>()
210 30 mode = 'div'
210 30 mode = 'div'
211 31
211 31
212 ---> 32 bar(mode)
212 ---> 32 bar(mode)
213 global bar = <function bar at ...>
213 global bar = <function bar at ...>
214 global mode = 'exit'
214 global mode = u'exit'
215 <BLANKLINE>
215 <BLANKLINE>
216 ... in bar(mode='exit')
216 ... in bar(mode=u'exit')
217 20 except:
217 20 except:
218 21 stat = 1
218 21 stat = 1
219 ---> 22 sysexit(stat, mode)
219 ---> 22 sysexit(stat, mode)
220 global sysexit = <function sysexit at ...>
220 global sysexit = <function sysexit at ...>
221 stat = 2
221 stat = 2
222 mode = 'exit'
222 mode = u'exit'
223 23 else:
223 23 else:
224 24 raise ValueError('Unknown mode')
224 24 raise ValueError('Unknown mode')
225 <BLANKLINE>
225 <BLANKLINE>
226 ... in sysexit(stat=2, mode='exit')
226 ... in sysexit(stat=2, mode=u'exit')
227 9
227 9
228 10 def sysexit(stat, mode):
228 10 def sysexit(stat, mode):
229 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
229 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
230 global SystemExit = undefined
230 global SystemExit = undefined
231 stat = 2
231 stat = 2
232 mode = 'exit'
232 mode = u'exit'
233 12
233 12
234 13 def bar(mode):
234 13 def bar(mode):
235 <BLANKLINE>
235 <BLANKLINE>
236 SystemExit: (2, 'Mode = exit')
236 SystemExit: (2, u'Mode = exit')
237 """
237 """
238
238
239
239
240 def test_runlines():
240 def test_runlines():
241 import textwrap
241 import textwrap
242 ip.runlines(['a = 10', 'a+=1'])
242 ip.runlines(['a = 10', 'a+=1'])
243 ip.runlines('assert a == 11\nassert 1')
243 ip.runlines('assert a == 11\nassert 1')
244
244
245 nt.assert_equals(ip.user_ns['a'], 11)
245 nt.assert_equals(ip.user_ns['a'], 11)
246 complex = textwrap.dedent("""
246 complex = textwrap.dedent("""
247 if 1:
247 if 1:
248 print "hello"
248 print "hello"
249 if 1:
249 if 1:
250 print "world"
250 print "world"
251
251
252 if 2:
252 if 2:
253 print "foo"
253 print "foo"
254
254
255 if 3:
255 if 3:
256 print "bar"
256 print "bar"
257
257
258 if 4:
258 if 4:
259 print "bar"
259 print "bar"
260
260
261 """)
261 """)
262 # Simply verifies that this kind of input is run
262 # Simply verifies that this kind of input is run
263 ip.runlines(complex)
263 ip.runlines(complex)
264
264
265
265
266 def test_db():
266 def test_db():
267 """Test the internal database used for variable persistence."""
267 """Test the internal database used for variable persistence."""
268 ip.db['__unittest_'] = 12
268 ip.db['__unittest_'] = 12
269 nt.assert_equals(ip.db['__unittest_'], 12)
269 nt.assert_equals(ip.db['__unittest_'], 12)
270 del ip.db['__unittest_']
270 del ip.db['__unittest_']
271 assert '__unittest_' not in ip.db
271 assert '__unittest_' not in ip.db
@@ -1,186 +1,186 b''
1 """Tests for code execution (%run and related), which is particularly tricky.
1 """Tests for code execution (%run and related), which is particularly tricky.
2
2
3 Because of how %run manages namespaces, and the fact that we are trying here to
3 Because of how %run manages namespaces, and the fact that we are trying here to
4 verify subtle object deletion and reference counting issues, the %run tests
4 verify subtle object deletion and reference counting issues, the %run tests
5 will be kept in this separate file. This makes it easier to aggregate in one
5 will be kept in this separate file. This makes it easier to aggregate in one
6 place the tricks needed to handle it; most other magics are much easier to test
6 place the tricks needed to handle it; most other magics are much easier to test
7 and we do so in a common test_magic file.
7 and we do so in a common test_magic file.
8 """
8 """
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18
18
19 import nose.tools as nt
19 import nose.tools as nt
20
20
21 from IPython.testing import decorators as dec
21 from IPython.testing import decorators as dec
22 from IPython.testing import tools as tt
22 from IPython.testing import tools as tt
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Test functions begin
25 # Test functions begin
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 def doctest_refbug():
28 def doctest_refbug():
29 """Very nasty problem with references held by multiple runs of a script.
29 """Very nasty problem with references held by multiple runs of a script.
30 See: https://bugs.launchpad.net/ipython/+bug/269966
30 See: https://bugs.launchpad.net/ipython/+bug/269966
31
31
32 In [1]: _ip.clear_main_mod_cache()
32 In [1]: _ip.clear_main_mod_cache()
33 # random
33 # random
34
34
35 In [2]: %run refbug
35 In [2]: %run refbug
36
36
37 In [3]: call_f()
37 In [3]: call_f()
38 lowercased: hello
38 lowercased: hello
39
39
40 In [4]: %run refbug
40 In [4]: %run refbug
41
41
42 In [5]: call_f()
42 In [5]: call_f()
43 lowercased: hello
43 lowercased: hello
44 lowercased: hello
44 lowercased: hello
45 """
45 """
46
46
47
47
48 def doctest_run_builtins():
48 def doctest_run_builtins():
49 r"""Check that %run doesn't damage __builtins__.
49 r"""Check that %run doesn't damage __builtins__.
50
50
51 In [1]: import tempfile
51 In [1]: import tempfile
52
52
53 In [2]: bid1 = id(__builtins__)
53 In [2]: bid1 = id(__builtins__)
54
54
55 In [3]: fname = tempfile.mkstemp('.py')[1]
55 In [3]: fname = tempfile.mkstemp('.py')[1]
56
56
57 In [3]: f = open(fname,'w')
57 In [3]: f = open(fname,'w')
58
58
59 In [4]: f.write('pass\n')
59 In [4]: f.write('pass\n')
60
60
61 In [5]: f.flush()
61 In [5]: f.flush()
62
62
63 In [6]: t1 = type(__builtins__)
63 In [6]: t1 = type(__builtins__)
64
64
65 In [7]: %run $fname
65 In [7]: %run $fname
66
66
67 In [7]: f.close()
67 In [7]: f.close()
68
68
69 In [8]: bid2 = id(__builtins__)
69 In [8]: bid2 = id(__builtins__)
70
70
71 In [9]: t2 = type(__builtins__)
71 In [9]: t2 = type(__builtins__)
72
72
73 In [10]: t1 == t2
73 In [10]: t1 == t2
74 Out[10]: True
74 Out[10]: True
75
75
76 In [10]: bid1 == bid2
76 In [10]: bid1 == bid2
77 Out[10]: True
77 Out[10]: True
78
78
79 In [12]: try:
79 In [12]: try:
80 ....: os.unlink(fname)
80 ....: os.unlink(fname)
81 ....: except:
81 ....: except:
82 ....: pass
82 ....: pass
83 ....:
83 ....:
84 """
84 """
85
85
86 def doctest_reset_del():
86 def doctest_reset_del():
87 """Test that resetting doesn't cause errors in __del__ methods.
87 """Test that resetting doesn't cause errors in __del__ methods.
88
88
89 In [2]: class A(object):
89 In [2]: class A(object):
90 ...: def __del__(self):
90 ...: def __del__(self):
91 ...: print str("Hi")
91 ...: print str("Hi")
92 ...:
92 ...:
93
93
94 In [3]: a = A()
94 In [3]: a = A()
95
95
96 In [4]: get_ipython().reset()
96 In [4]: get_ipython().reset()
97 Hi
97 Hi
98
98
99 In [5]: 1+1
99 In [5]: 1+1
100 Out[5]: 2
100 Out[5]: 2
101 """
101 """
102
102
103 # For some tests, it will be handy to organize them in a class with a common
103 # For some tests, it will be handy to organize them in a class with a common
104 # setup that makes a temp file
104 # setup that makes a temp file
105
105
106 class TestMagicRunPass(tt.TempFileMixin):
106 class TestMagicRunPass(tt.TempFileMixin):
107
107
108 def setup(self):
108 def setup(self):
109 """Make a valid python temp file."""
109 """Make a valid python temp file."""
110 self.mktmp('pass\n')
110 self.mktmp('pass\n')
111
111
112 def run_tmpfile(self):
112 def run_tmpfile(self):
113 _ip = get_ipython()
113 _ip = get_ipython()
114 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
114 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
115 # See below and ticket https://bugs.launchpad.net/bugs/366353
115 # See below and ticket https://bugs.launchpad.net/bugs/366353
116 _ip.magic('run %s' % self.fname)
116 _ip.magic('run %s' % self.fname)
117
117
118 def test_builtins_id(self):
118 def test_builtins_id(self):
119 """Check that %run doesn't damage __builtins__ """
119 """Check that %run doesn't damage __builtins__ """
120 _ip = get_ipython()
120 _ip = get_ipython()
121 # Test that the id of __builtins__ is not modified by %run
121 # Test that the id of __builtins__ is not modified by %run
122 bid1 = id(_ip.user_ns['__builtins__'])
122 bid1 = id(_ip.user_ns['__builtins__'])
123 self.run_tmpfile()
123 self.run_tmpfile()
124 bid2 = id(_ip.user_ns['__builtins__'])
124 bid2 = id(_ip.user_ns['__builtins__'])
125 tt.assert_equals(bid1, bid2)
125 tt.assert_equals(bid1, bid2)
126
126
127 def test_builtins_type(self):
127 def test_builtins_type(self):
128 """Check that the type of __builtins__ doesn't change with %run.
128 """Check that the type of __builtins__ doesn't change with %run.
129
129
130 However, the above could pass if __builtins__ was already modified to
130 However, the above could pass if __builtins__ was already modified to
131 be a dict (it should be a module) by a previous use of %run. So we
131 be a dict (it should be a module) by a previous use of %run. So we
132 also check explicitly that it really is a module:
132 also check explicitly that it really is a module:
133 """
133 """
134 _ip = get_ipython()
134 _ip = get_ipython()
135 self.run_tmpfile()
135 self.run_tmpfile()
136 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
136 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
137
137
138 def test_prompts(self):
138 def test_prompts(self):
139 """Test that prompts correctly generate after %run"""
139 """Test that prompts correctly generate after %run"""
140 self.run_tmpfile()
140 self.run_tmpfile()
141 _ip = get_ipython()
141 _ip = get_ipython()
142 p2 = str(_ip.displayhook.prompt2).strip()
142 p2 = str(_ip.displayhook.prompt2).strip()
143 nt.assert_equals(p2[:3], '...')
143 nt.assert_equals(p2[:3], '...')
144
144
145
145
146 class TestMagicRunSimple(tt.TempFileMixin):
146 class TestMagicRunSimple(tt.TempFileMixin):
147
147
148 def test_simpledef(self):
148 def test_simpledef(self):
149 """Test that simple class definitions work."""
149 """Test that simple class definitions work."""
150 src = ("class foo: pass\n"
150 src = ("class foo: pass\n"
151 "def f(): return foo()")
151 "def f(): return foo()")
152 self.mktmp(src)
152 self.mktmp(src)
153 _ip.magic('run %s' % self.fname)
153 _ip.magic('run %s' % self.fname)
154 _ip.runlines('t = isinstance(f(), foo)')
154 _ip.runlines('t = isinstance(f(), foo)')
155 nt.assert_true(_ip.user_ns['t'])
155 nt.assert_true(_ip.user_ns['t'])
156
156
157 # We have to skip these in win32 because getoutputerr() crashes,
157 # We have to skip these in win32 because getoutputerr() crashes,
158 # due to the fact that subprocess does not support close_fds when
158 # due to the fact that subprocess does not support close_fds when
159 # redirecting stdout/err. So unless someone who knows more tells us how to
159 # redirecting stdout/err. So unless someone who knows more tells us how to
160 # implement getoutputerr() in win32, we're stuck avoiding these.
160 # implement getoutputerr() in win32, we're stuck avoiding these.
161 @dec.skip_win32
161 @dec.skip_win32
162 def test_obj_del(self):
162 def test_obj_del(self):
163 """Test that object's __del__ methods are called on exit."""
163 """Test that object's __del__ methods are called on exit."""
164
164
165 # This test is known to fail on win32.
165 # This test is known to fail on win32.
166 # See ticket https://bugs.launchpad.net/bugs/366334
166 # See ticket https://bugs.launchpad.net/bugs/366334
167 src = ("class A(object):\n"
167 src = ("class A(object):\n"
168 " def __del__(self):\n"
168 " def __del__(self):\n"
169 " print 'object A deleted'\n"
169 " print 'object A deleted'\n"
170 "a = A()\n")
170 "a = A()\n")
171 self.mktmp(src)
171 self.mktmp(src)
172 tt.ipexec_validate(self.fname, 'object A deleted')
172 tt.ipexec_validate(self.fname, 'object A deleted')
173
173
174 @dec.skip_win32
174 @dec.skip_win32
175 def test_tclass(self):
175 def test_tclass(self):
176 mydir = os.path.dirname(__file__)
176 mydir = os.path.dirname(__file__)
177 tc = os.path.join(mydir, 'tclass')
177 tc = os.path.join(mydir, 'tclass')
178 src = ("%%run '%s' C-first\n"
178 src = ("%%run '%s' C-first\n"
179 "%%run '%s' C-second\n") % (tc, tc)
179 "%%run '%s' C-second\n") % (tc, tc)
180 self.mktmp(src, '.ipy')
180 self.mktmp(src, '.ipy')
181 out = """\
181 out = """\
182 ARGV 1-: ['C-first']
182 ARGV 1-: [u'C-first']
183 ARGV 1-: ['C-second']
183 ARGV 1-: [u'C-second']
184 tclass.py: deleting object: C-first
184 tclass.py: deleting object: C-first
185 """
185 """
186 tt.ipexec_validate(self.fname, out)
186 tt.ipexec_validate(self.fname, out)
General Comments 0
You need to be logged in to leave comments. Login now