##// END OF EJS Templates
Merge pull request #12208 from mwageringel/unicode_identifiers...
Matthias Bussonnier -
r25596:4b3670e1 merge
parent child Browse files
Show More
@@ -1,354 +1,354 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Implementations for various useful completers.
2 """Implementations for various useful completers.
3
3
4 These are all loaded by default by IPython.
4 These are all loaded by default by IPython.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010-2011 The IPython Development Team.
7 # Copyright (C) 2010-2011 The IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the BSD License.
9 # Distributed under the terms of the BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 # Stdlib imports
18 # Stdlib imports
19 import glob
19 import glob
20 import inspect
20 import inspect
21 import os
21 import os
22 import re
22 import re
23 import sys
23 import sys
24 from importlib import import_module
24 from importlib import import_module
25 from importlib.machinery import all_suffixes
25 from importlib.machinery import all_suffixes
26
26
27
27
28 # Third-party imports
28 # Third-party imports
29 from time import time
29 from time import time
30 from zipimport import zipimporter
30 from zipimport import zipimporter
31
31
32 # Our own imports
32 # Our own imports
33 from .completer import expand_user, compress_user
33 from .completer import expand_user, compress_user
34 from .error import TryNext
34 from .error import TryNext
35 from ..utils._process_common import arg_split
35 from ..utils._process_common import arg_split
36
36
37 # FIXME: this should be pulled in with the right call via the component system
37 # FIXME: this should be pulled in with the right call via the component system
38 from IPython import get_ipython
38 from IPython import get_ipython
39
39
40 from typing import List
40 from typing import List
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Globals and constants
43 # Globals and constants
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 _suffixes = all_suffixes()
45 _suffixes = all_suffixes()
46
46
47 # Time in seconds after which the rootmodules will be stored permanently in the
47 # Time in seconds after which the rootmodules will be stored permanently in the
48 # ipython ip.db database (kept in the user's .ipython dir).
48 # ipython ip.db database (kept in the user's .ipython dir).
49 TIMEOUT_STORAGE = 2
49 TIMEOUT_STORAGE = 2
50
50
51 # Time in seconds after which we give up
51 # Time in seconds after which we give up
52 TIMEOUT_GIVEUP = 20
52 TIMEOUT_GIVEUP = 20
53
53
54 # Regular expression for the python import statement
54 # Regular expression for the python import statement
55 import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
55 import_re = re.compile(r'(?P<name>[^\W\d]\w*?)'
56 r'(?P<package>[/\\]__init__)?'
56 r'(?P<package>[/\\]__init__)?'
57 r'(?P<suffix>%s)$' %
57 r'(?P<suffix>%s)$' %
58 r'|'.join(re.escape(s) for s in _suffixes))
58 r'|'.join(re.escape(s) for s in _suffixes))
59
59
60 # RE for the ipython %run command (python + ipython scripts)
60 # RE for the ipython %run command (python + ipython scripts)
61 magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$')
61 magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$')
62
62
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 # Local utilities
64 # Local utilities
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67 def module_list(path):
67 def module_list(path):
68 """
68 """
69 Return the list containing the names of the modules available in the given
69 Return the list containing the names of the modules available in the given
70 folder.
70 folder.
71 """
71 """
72 # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
72 # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
73 if path == '':
73 if path == '':
74 path = '.'
74 path = '.'
75
75
76 # A few local constants to be used in loops below
76 # A few local constants to be used in loops below
77 pjoin = os.path.join
77 pjoin = os.path.join
78
78
79 if os.path.isdir(path):
79 if os.path.isdir(path):
80 # Build a list of all files in the directory and all files
80 # Build a list of all files in the directory and all files
81 # in its subdirectories. For performance reasons, do not
81 # in its subdirectories. For performance reasons, do not
82 # recurse more than one level into subdirectories.
82 # recurse more than one level into subdirectories.
83 files = []
83 files = []
84 for root, dirs, nondirs in os.walk(path, followlinks=True):
84 for root, dirs, nondirs in os.walk(path, followlinks=True):
85 subdir = root[len(path)+1:]
85 subdir = root[len(path)+1:]
86 if subdir:
86 if subdir:
87 files.extend(pjoin(subdir, f) for f in nondirs)
87 files.extend(pjoin(subdir, f) for f in nondirs)
88 dirs[:] = [] # Do not recurse into additional subdirectories.
88 dirs[:] = [] # Do not recurse into additional subdirectories.
89 else:
89 else:
90 files.extend(nondirs)
90 files.extend(nondirs)
91
91
92 else:
92 else:
93 try:
93 try:
94 files = list(zipimporter(path)._files.keys())
94 files = list(zipimporter(path)._files.keys())
95 except:
95 except:
96 files = []
96 files = []
97
97
98 # Build a list of modules which match the import_re regex.
98 # Build a list of modules which match the import_re regex.
99 modules = []
99 modules = []
100 for f in files:
100 for f in files:
101 m = import_re.match(f)
101 m = import_re.match(f)
102 if m:
102 if m:
103 modules.append(m.group('name'))
103 modules.append(m.group('name'))
104 return list(set(modules))
104 return list(set(modules))
105
105
106
106
107 def get_root_modules():
107 def get_root_modules():
108 """
108 """
109 Returns a list containing the names of all the modules available in the
109 Returns a list containing the names of all the modules available in the
110 folders of the pythonpath.
110 folders of the pythonpath.
111
111
112 ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
112 ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
113 """
113 """
114 ip = get_ipython()
114 ip = get_ipython()
115 if ip is None:
115 if ip is None:
116 # No global shell instance to store cached list of modules.
116 # No global shell instance to store cached list of modules.
117 # Don't try to scan for modules every time.
117 # Don't try to scan for modules every time.
118 return list(sys.builtin_module_names)
118 return list(sys.builtin_module_names)
119
119
120 rootmodules_cache = ip.db.get('rootmodules_cache', {})
120 rootmodules_cache = ip.db.get('rootmodules_cache', {})
121 rootmodules = list(sys.builtin_module_names)
121 rootmodules = list(sys.builtin_module_names)
122 start_time = time()
122 start_time = time()
123 store = False
123 store = False
124 for path in sys.path:
124 for path in sys.path:
125 try:
125 try:
126 modules = rootmodules_cache[path]
126 modules = rootmodules_cache[path]
127 except KeyError:
127 except KeyError:
128 modules = module_list(path)
128 modules = module_list(path)
129 try:
129 try:
130 modules.remove('__init__')
130 modules.remove('__init__')
131 except ValueError:
131 except ValueError:
132 pass
132 pass
133 if path not in ('', '.'): # cwd modules should not be cached
133 if path not in ('', '.'): # cwd modules should not be cached
134 rootmodules_cache[path] = modules
134 rootmodules_cache[path] = modules
135 if time() - start_time > TIMEOUT_STORAGE and not store:
135 if time() - start_time > TIMEOUT_STORAGE and not store:
136 store = True
136 store = True
137 print("\nCaching the list of root modules, please wait!")
137 print("\nCaching the list of root modules, please wait!")
138 print("(This will only be done once - type '%rehashx' to "
138 print("(This will only be done once - type '%rehashx' to "
139 "reset cache!)\n")
139 "reset cache!)\n")
140 sys.stdout.flush()
140 sys.stdout.flush()
141 if time() - start_time > TIMEOUT_GIVEUP:
141 if time() - start_time > TIMEOUT_GIVEUP:
142 print("This is taking too long, we give up.\n")
142 print("This is taking too long, we give up.\n")
143 return []
143 return []
144 rootmodules.extend(modules)
144 rootmodules.extend(modules)
145 if store:
145 if store:
146 ip.db['rootmodules_cache'] = rootmodules_cache
146 ip.db['rootmodules_cache'] = rootmodules_cache
147 rootmodules = list(set(rootmodules))
147 rootmodules = list(set(rootmodules))
148 return rootmodules
148 return rootmodules
149
149
150
150
151 def is_importable(module, attr, only_modules):
151 def is_importable(module, attr, only_modules):
152 if only_modules:
152 if only_modules:
153 return inspect.ismodule(getattr(module, attr))
153 return inspect.ismodule(getattr(module, attr))
154 else:
154 else:
155 return not(attr[:2] == '__' and attr[-2:] == '__')
155 return not(attr[:2] == '__' and attr[-2:] == '__')
156
156
157
157
158 def try_import(mod: str, only_modules=False) -> List[str]:
158 def try_import(mod: str, only_modules=False) -> List[str]:
159 """
159 """
160 Try to import given module and return list of potential completions.
160 Try to import given module and return list of potential completions.
161 """
161 """
162 mod = mod.rstrip('.')
162 mod = mod.rstrip('.')
163 try:
163 try:
164 m = import_module(mod)
164 m = import_module(mod)
165 except:
165 except:
166 return []
166 return []
167
167
168 m_is_init = '__init__' in (getattr(m, '__file__', '') or '')
168 m_is_init = '__init__' in (getattr(m, '__file__', '') or '')
169
169
170 completions = []
170 completions = []
171 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
171 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
172 completions.extend( [attr for attr in dir(m) if
172 completions.extend( [attr for attr in dir(m) if
173 is_importable(m, attr, only_modules)])
173 is_importable(m, attr, only_modules)])
174
174
175 completions.extend(getattr(m, '__all__', []))
175 completions.extend(getattr(m, '__all__', []))
176 if m_is_init:
176 if m_is_init:
177 completions.extend(module_list(os.path.dirname(m.__file__)))
177 completions.extend(module_list(os.path.dirname(m.__file__)))
178 completions_set = {c for c in completions if isinstance(c, str)}
178 completions_set = {c for c in completions if isinstance(c, str)}
179 completions_set.discard('__init__')
179 completions_set.discard('__init__')
180 return list(completions_set)
180 return list(completions_set)
181
181
182
182
183 #-----------------------------------------------------------------------------
183 #-----------------------------------------------------------------------------
184 # Completion-related functions.
184 # Completion-related functions.
185 #-----------------------------------------------------------------------------
185 #-----------------------------------------------------------------------------
186
186
187 def quick_completer(cmd, completions):
187 def quick_completer(cmd, completions):
188 r""" Easily create a trivial completer for a command.
188 r""" Easily create a trivial completer for a command.
189
189
190 Takes either a list of completions, or all completions in string (that will
190 Takes either a list of completions, or all completions in string (that will
191 be split on whitespace).
191 be split on whitespace).
192
192
193 Example::
193 Example::
194
194
195 [d:\ipython]|1> import ipy_completers
195 [d:\ipython]|1> import ipy_completers
196 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
196 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
197 [d:\ipython]|3> foo b<TAB>
197 [d:\ipython]|3> foo b<TAB>
198 bar baz
198 bar baz
199 [d:\ipython]|3> foo ba
199 [d:\ipython]|3> foo ba
200 """
200 """
201
201
202 if isinstance(completions, str):
202 if isinstance(completions, str):
203 completions = completions.split()
203 completions = completions.split()
204
204
205 def do_complete(self, event):
205 def do_complete(self, event):
206 return completions
206 return completions
207
207
208 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
208 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
209
209
210 def module_completion(line):
210 def module_completion(line):
211 """
211 """
212 Returns a list containing the completion possibilities for an import line.
212 Returns a list containing the completion possibilities for an import line.
213
213
214 The line looks like this :
214 The line looks like this :
215 'import xml.d'
215 'import xml.d'
216 'from xml.dom import'
216 'from xml.dom import'
217 """
217 """
218
218
219 words = line.split(' ')
219 words = line.split(' ')
220 nwords = len(words)
220 nwords = len(words)
221
221
222 # from whatever <tab> -> 'import '
222 # from whatever <tab> -> 'import '
223 if nwords == 3 and words[0] == 'from':
223 if nwords == 3 and words[0] == 'from':
224 return ['import ']
224 return ['import ']
225
225
226 # 'from xy<tab>' or 'import xy<tab>'
226 # 'from xy<tab>' or 'import xy<tab>'
227 if nwords < 3 and (words[0] in {'%aimport', 'import', 'from'}) :
227 if nwords < 3 and (words[0] in {'%aimport', 'import', 'from'}) :
228 if nwords == 1:
228 if nwords == 1:
229 return get_root_modules()
229 return get_root_modules()
230 mod = words[1].split('.')
230 mod = words[1].split('.')
231 if len(mod) < 2:
231 if len(mod) < 2:
232 return get_root_modules()
232 return get_root_modules()
233 completion_list = try_import('.'.join(mod[:-1]), True)
233 completion_list = try_import('.'.join(mod[:-1]), True)
234 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
234 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
235
235
236 # 'from xyz import abc<tab>'
236 # 'from xyz import abc<tab>'
237 if nwords >= 3 and words[0] == 'from':
237 if nwords >= 3 and words[0] == 'from':
238 mod = words[1]
238 mod = words[1]
239 return try_import(mod)
239 return try_import(mod)
240
240
241 #-----------------------------------------------------------------------------
241 #-----------------------------------------------------------------------------
242 # Completers
242 # Completers
243 #-----------------------------------------------------------------------------
243 #-----------------------------------------------------------------------------
244 # These all have the func(self, event) signature to be used as custom
244 # These all have the func(self, event) signature to be used as custom
245 # completers
245 # completers
246
246
247 def module_completer(self,event):
247 def module_completer(self,event):
248 """Give completions after user has typed 'import ...' or 'from ...'"""
248 """Give completions after user has typed 'import ...' or 'from ...'"""
249
249
250 # This works in all versions of python. While 2.5 has
250 # This works in all versions of python. While 2.5 has
251 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
251 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
252 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
252 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
253 # of possibly problematic side effects.
253 # of possibly problematic side effects.
254 # This search the folders in the sys.path for available modules.
254 # This search the folders in the sys.path for available modules.
255
255
256 return module_completion(event.line)
256 return module_completion(event.line)
257
257
258 # FIXME: there's a lot of logic common to the run, cd and builtin file
258 # FIXME: there's a lot of logic common to the run, cd and builtin file
259 # completers, that is currently reimplemented in each.
259 # completers, that is currently reimplemented in each.
260
260
261 def magic_run_completer(self, event):
261 def magic_run_completer(self, event):
262 """Complete files that end in .py or .ipy or .ipynb for the %run command.
262 """Complete files that end in .py or .ipy or .ipynb for the %run command.
263 """
263 """
264 comps = arg_split(event.line, strict=False)
264 comps = arg_split(event.line, strict=False)
265 # relpath should be the current token that we need to complete.
265 # relpath should be the current token that we need to complete.
266 if (len(comps) > 1) and (not event.line.endswith(' ')):
266 if (len(comps) > 1) and (not event.line.endswith(' ')):
267 relpath = comps[-1].strip("'\"")
267 relpath = comps[-1].strip("'\"")
268 else:
268 else:
269 relpath = ''
269 relpath = ''
270
270
271 #print("\nev=", event) # dbg
271 #print("\nev=", event) # dbg
272 #print("rp=", relpath) # dbg
272 #print("rp=", relpath) # dbg
273 #print('comps=', comps) # dbg
273 #print('comps=', comps) # dbg
274
274
275 lglob = glob.glob
275 lglob = glob.glob
276 isdir = os.path.isdir
276 isdir = os.path.isdir
277 relpath, tilde_expand, tilde_val = expand_user(relpath)
277 relpath, tilde_expand, tilde_val = expand_user(relpath)
278
278
279 # Find if the user has already typed the first filename, after which we
279 # Find if the user has already typed the first filename, after which we
280 # should complete on all files, since after the first one other files may
280 # should complete on all files, since after the first one other files may
281 # be arguments to the input script.
281 # be arguments to the input script.
282
282
283 if any(magic_run_re.match(c) for c in comps):
283 if any(magic_run_re.match(c) for c in comps):
284 matches = [f.replace('\\','/') + ('/' if isdir(f) else '')
284 matches = [f.replace('\\','/') + ('/' if isdir(f) else '')
285 for f in lglob(relpath+'*')]
285 for f in lglob(relpath+'*')]
286 else:
286 else:
287 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
287 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
288 pys = [f.replace('\\','/')
288 pys = [f.replace('\\','/')
289 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
289 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
290 lglob(relpath+'*.ipynb') + lglob(relpath + '*.pyw')]
290 lglob(relpath+'*.ipynb') + lglob(relpath + '*.pyw')]
291
291
292 matches = dirs + pys
292 matches = dirs + pys
293
293
294 #print('run comp:', dirs+pys) # dbg
294 #print('run comp:', dirs+pys) # dbg
295 return [compress_user(p, tilde_expand, tilde_val) for p in matches]
295 return [compress_user(p, tilde_expand, tilde_val) for p in matches]
296
296
297
297
298 def cd_completer(self, event):
298 def cd_completer(self, event):
299 """Completer function for cd, which only returns directories."""
299 """Completer function for cd, which only returns directories."""
300 ip = get_ipython()
300 ip = get_ipython()
301 relpath = event.symbol
301 relpath = event.symbol
302
302
303 #print(event) # dbg
303 #print(event) # dbg
304 if event.line.endswith('-b') or ' -b ' in event.line:
304 if event.line.endswith('-b') or ' -b ' in event.line:
305 # return only bookmark completions
305 # return only bookmark completions
306 bkms = self.db.get('bookmarks', None)
306 bkms = self.db.get('bookmarks', None)
307 if bkms:
307 if bkms:
308 return bkms.keys()
308 return bkms.keys()
309 else:
309 else:
310 return []
310 return []
311
311
312 if event.symbol == '-':
312 if event.symbol == '-':
313 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
313 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
314 # jump in directory history by number
314 # jump in directory history by number
315 fmt = '-%0' + width_dh +'d [%s]'
315 fmt = '-%0' + width_dh +'d [%s]'
316 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
316 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
317 if len(ents) > 1:
317 if len(ents) > 1:
318 return ents
318 return ents
319 return []
319 return []
320
320
321 if event.symbol.startswith('--'):
321 if event.symbol.startswith('--'):
322 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
322 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
323
323
324 # Expand ~ in path and normalize directory separators.
324 # Expand ~ in path and normalize directory separators.
325 relpath, tilde_expand, tilde_val = expand_user(relpath)
325 relpath, tilde_expand, tilde_val = expand_user(relpath)
326 relpath = relpath.replace('\\','/')
326 relpath = relpath.replace('\\','/')
327
327
328 found = []
328 found = []
329 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
329 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
330 if os.path.isdir(f)]:
330 if os.path.isdir(f)]:
331 if ' ' in d:
331 if ' ' in d:
332 # we don't want to deal with any of that, complex code
332 # we don't want to deal with any of that, complex code
333 # for this is elsewhere
333 # for this is elsewhere
334 raise TryNext
334 raise TryNext
335
335
336 found.append(d)
336 found.append(d)
337
337
338 if not found:
338 if not found:
339 if os.path.isdir(relpath):
339 if os.path.isdir(relpath):
340 return [compress_user(relpath, tilde_expand, tilde_val)]
340 return [compress_user(relpath, tilde_expand, tilde_val)]
341
341
342 # if no completions so far, try bookmarks
342 # if no completions so far, try bookmarks
343 bks = self.db.get('bookmarks',{})
343 bks = self.db.get('bookmarks',{})
344 bkmatches = [s for s in bks if s.startswith(event.symbol)]
344 bkmatches = [s for s in bks if s.startswith(event.symbol)]
345 if bkmatches:
345 if bkmatches:
346 return bkmatches
346 return bkmatches
347
347
348 raise TryNext
348 raise TryNext
349
349
350 return [compress_user(p, tilde_expand, tilde_val) for p in found]
350 return [compress_user(p, tilde_expand, tilde_val) for p in found]
351
351
352 def reset_completer(self, event):
352 def reset_completer(self, event):
353 "A completer for %reset magic"
353 "A completer for %reset magic"
354 return '-f -s in out array dhist'.split()
354 return '-f -s in out array dhist'.split()
@@ -1,536 +1,536 b''
1 """DEPRECATED: Input transformer classes to support IPython special syntax.
1 """DEPRECATED: Input transformer classes to support IPython special syntax.
2
2
3 This module was deprecated in IPython 7.0, in favour of inputtransformer2.
3 This module was deprecated in IPython 7.0, in favour of inputtransformer2.
4
4
5 This includes the machinery to recognise and transform ``%magic`` commands,
5 This includes the machinery to recognise and transform ``%magic`` commands,
6 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
6 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
7 """
7 """
8 import abc
8 import abc
9 import functools
9 import functools
10 import re
10 import re
11 import tokenize
11 import tokenize
12 from tokenize import generate_tokens, untokenize, TokenError
12 from tokenize import generate_tokens, untokenize, TokenError
13 from io import StringIO
13 from io import StringIO
14
14
15 from IPython.core.splitinput import LineInfo
15 from IPython.core.splitinput import LineInfo
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Globals
18 # Globals
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 # The escape sequences that define the syntax transformations IPython will
21 # The escape sequences that define the syntax transformations IPython will
22 # apply to user input. These can NOT be just changed here: many regular
22 # apply to user input. These can NOT be just changed here: many regular
23 # expressions and other parts of the code may use their hardcoded values, and
23 # expressions and other parts of the code may use their hardcoded values, and
24 # for all intents and purposes they constitute the 'IPython syntax', so they
24 # for all intents and purposes they constitute the 'IPython syntax', so they
25 # should be considered fixed.
25 # should be considered fixed.
26
26
27 ESC_SHELL = '!' # Send line to underlying system shell
27 ESC_SHELL = '!' # Send line to underlying system shell
28 ESC_SH_CAP = '!!' # Send line to system shell and capture output
28 ESC_SH_CAP = '!!' # Send line to system shell and capture output
29 ESC_HELP = '?' # Find information about object
29 ESC_HELP = '?' # Find information about object
30 ESC_HELP2 = '??' # Find extra-detailed information about object
30 ESC_HELP2 = '??' # Find extra-detailed information about object
31 ESC_MAGIC = '%' # Call magic function
31 ESC_MAGIC = '%' # Call magic function
32 ESC_MAGIC2 = '%%' # Call cell-magic function
32 ESC_MAGIC2 = '%%' # Call cell-magic function
33 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
33 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
34 ESC_QUOTE2 = ';' # Quote all args as a single string, call
34 ESC_QUOTE2 = ';' # Quote all args as a single string, call
35 ESC_PAREN = '/' # Call first argument with rest of line as arguments
35 ESC_PAREN = '/' # Call first argument with rest of line as arguments
36
36
37 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
37 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
38 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
38 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
39 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
39 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
40
40
41
41
42 class InputTransformer(metaclass=abc.ABCMeta):
42 class InputTransformer(metaclass=abc.ABCMeta):
43 """Abstract base class for line-based input transformers."""
43 """Abstract base class for line-based input transformers."""
44
44
45 @abc.abstractmethod
45 @abc.abstractmethod
46 def push(self, line):
46 def push(self, line):
47 """Send a line of input to the transformer, returning the transformed
47 """Send a line of input to the transformer, returning the transformed
48 input or None if the transformer is waiting for more input.
48 input or None if the transformer is waiting for more input.
49
49
50 Must be overridden by subclasses.
50 Must be overridden by subclasses.
51
51
52 Implementations may raise ``SyntaxError`` if the input is invalid. No
52 Implementations may raise ``SyntaxError`` if the input is invalid. No
53 other exceptions may be raised.
53 other exceptions may be raised.
54 """
54 """
55 pass
55 pass
56
56
57 @abc.abstractmethod
57 @abc.abstractmethod
58 def reset(self):
58 def reset(self):
59 """Return, transformed any lines that the transformer has accumulated,
59 """Return, transformed any lines that the transformer has accumulated,
60 and reset its internal state.
60 and reset its internal state.
61
61
62 Must be overridden by subclasses.
62 Must be overridden by subclasses.
63 """
63 """
64 pass
64 pass
65
65
66 @classmethod
66 @classmethod
67 def wrap(cls, func):
67 def wrap(cls, func):
68 """Can be used by subclasses as a decorator, to return a factory that
68 """Can be used by subclasses as a decorator, to return a factory that
69 will allow instantiation with the decorated object.
69 will allow instantiation with the decorated object.
70 """
70 """
71 @functools.wraps(func)
71 @functools.wraps(func)
72 def transformer_factory(**kwargs):
72 def transformer_factory(**kwargs):
73 return cls(func, **kwargs)
73 return cls(func, **kwargs)
74
74
75 return transformer_factory
75 return transformer_factory
76
76
77 class StatelessInputTransformer(InputTransformer):
77 class StatelessInputTransformer(InputTransformer):
78 """Wrapper for a stateless input transformer implemented as a function."""
78 """Wrapper for a stateless input transformer implemented as a function."""
79 def __init__(self, func):
79 def __init__(self, func):
80 self.func = func
80 self.func = func
81
81
82 def __repr__(self):
82 def __repr__(self):
83 return "StatelessInputTransformer(func={0!r})".format(self.func)
83 return "StatelessInputTransformer(func={0!r})".format(self.func)
84
84
85 def push(self, line):
85 def push(self, line):
86 """Send a line of input to the transformer, returning the
86 """Send a line of input to the transformer, returning the
87 transformed input."""
87 transformed input."""
88 return self.func(line)
88 return self.func(line)
89
89
90 def reset(self):
90 def reset(self):
91 """No-op - exists for compatibility."""
91 """No-op - exists for compatibility."""
92 pass
92 pass
93
93
94 class CoroutineInputTransformer(InputTransformer):
94 class CoroutineInputTransformer(InputTransformer):
95 """Wrapper for an input transformer implemented as a coroutine."""
95 """Wrapper for an input transformer implemented as a coroutine."""
96 def __init__(self, coro, **kwargs):
96 def __init__(self, coro, **kwargs):
97 # Prime it
97 # Prime it
98 self.coro = coro(**kwargs)
98 self.coro = coro(**kwargs)
99 next(self.coro)
99 next(self.coro)
100
100
101 def __repr__(self):
101 def __repr__(self):
102 return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
102 return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
103
103
104 def push(self, line):
104 def push(self, line):
105 """Send a line of input to the transformer, returning the
105 """Send a line of input to the transformer, returning the
106 transformed input or None if the transformer is waiting for more
106 transformed input or None if the transformer is waiting for more
107 input.
107 input.
108 """
108 """
109 return self.coro.send(line)
109 return self.coro.send(line)
110
110
111 def reset(self):
111 def reset(self):
112 """Return, transformed any lines that the transformer has
112 """Return, transformed any lines that the transformer has
113 accumulated, and reset its internal state.
113 accumulated, and reset its internal state.
114 """
114 """
115 return self.coro.send(None)
115 return self.coro.send(None)
116
116
117 class TokenInputTransformer(InputTransformer):
117 class TokenInputTransformer(InputTransformer):
118 """Wrapper for a token-based input transformer.
118 """Wrapper for a token-based input transformer.
119
119
120 func should accept a list of tokens (5-tuples, see tokenize docs), and
120 func should accept a list of tokens (5-tuples, see tokenize docs), and
121 return an iterable which can be passed to tokenize.untokenize().
121 return an iterable which can be passed to tokenize.untokenize().
122 """
122 """
123 def __init__(self, func):
123 def __init__(self, func):
124 self.func = func
124 self.func = func
125 self.buf = []
125 self.buf = []
126 self.reset_tokenizer()
126 self.reset_tokenizer()
127
127
128 def reset_tokenizer(self):
128 def reset_tokenizer(self):
129 it = iter(self.buf)
129 it = iter(self.buf)
130 self.tokenizer = generate_tokens(it.__next__)
130 self.tokenizer = generate_tokens(it.__next__)
131
131
132 def push(self, line):
132 def push(self, line):
133 self.buf.append(line + '\n')
133 self.buf.append(line + '\n')
134 if all(l.isspace() for l in self.buf):
134 if all(l.isspace() for l in self.buf):
135 return self.reset()
135 return self.reset()
136
136
137 tokens = []
137 tokens = []
138 stop_at_NL = False
138 stop_at_NL = False
139 try:
139 try:
140 for intok in self.tokenizer:
140 for intok in self.tokenizer:
141 tokens.append(intok)
141 tokens.append(intok)
142 t = intok[0]
142 t = intok[0]
143 if t == tokenize.NEWLINE or (stop_at_NL and t == tokenize.NL):
143 if t == tokenize.NEWLINE or (stop_at_NL and t == tokenize.NL):
144 # Stop before we try to pull a line we don't have yet
144 # Stop before we try to pull a line we don't have yet
145 break
145 break
146 elif t == tokenize.ERRORTOKEN:
146 elif t == tokenize.ERRORTOKEN:
147 stop_at_NL = True
147 stop_at_NL = True
148 except TokenError:
148 except TokenError:
149 # Multi-line statement - stop and try again with the next line
149 # Multi-line statement - stop and try again with the next line
150 self.reset_tokenizer()
150 self.reset_tokenizer()
151 return None
151 return None
152
152
153 return self.output(tokens)
153 return self.output(tokens)
154
154
155 def output(self, tokens):
155 def output(self, tokens):
156 self.buf.clear()
156 self.buf.clear()
157 self.reset_tokenizer()
157 self.reset_tokenizer()
158 return untokenize(self.func(tokens)).rstrip('\n')
158 return untokenize(self.func(tokens)).rstrip('\n')
159
159
160 def reset(self):
160 def reset(self):
161 l = ''.join(self.buf)
161 l = ''.join(self.buf)
162 self.buf.clear()
162 self.buf.clear()
163 self.reset_tokenizer()
163 self.reset_tokenizer()
164 if l:
164 if l:
165 return l.rstrip('\n')
165 return l.rstrip('\n')
166
166
167 class assemble_python_lines(TokenInputTransformer):
167 class assemble_python_lines(TokenInputTransformer):
168 def __init__(self):
168 def __init__(self):
169 super(assemble_python_lines, self).__init__(None)
169 super(assemble_python_lines, self).__init__(None)
170
170
171 def output(self, tokens):
171 def output(self, tokens):
172 return self.reset()
172 return self.reset()
173
173
174 @CoroutineInputTransformer.wrap
174 @CoroutineInputTransformer.wrap
175 def assemble_logical_lines():
175 def assemble_logical_lines():
176 r"""Join lines following explicit line continuations (\)"""
176 r"""Join lines following explicit line continuations (\)"""
177 line = ''
177 line = ''
178 while True:
178 while True:
179 line = (yield line)
179 line = (yield line)
180 if not line or line.isspace():
180 if not line or line.isspace():
181 continue
181 continue
182
182
183 parts = []
183 parts = []
184 while line is not None:
184 while line is not None:
185 if line.endswith('\\') and (not has_comment(line)):
185 if line.endswith('\\') and (not has_comment(line)):
186 parts.append(line[:-1])
186 parts.append(line[:-1])
187 line = (yield None) # Get another line
187 line = (yield None) # Get another line
188 else:
188 else:
189 parts.append(line)
189 parts.append(line)
190 break
190 break
191
191
192 # Output
192 # Output
193 line = ''.join(parts)
193 line = ''.join(parts)
194
194
195 # Utilities
195 # Utilities
196 def _make_help_call(target, esc, lspace, next_input=None):
196 def _make_help_call(target, esc, lspace, next_input=None):
197 """Prepares a pinfo(2)/psearch call from a target name and the escape
197 """Prepares a pinfo(2)/psearch call from a target name and the escape
198 (i.e. ? or ??)"""
198 (i.e. ? or ??)"""
199 method = 'pinfo2' if esc == '??' \
199 method = 'pinfo2' if esc == '??' \
200 else 'psearch' if '*' in target \
200 else 'psearch' if '*' in target \
201 else 'pinfo'
201 else 'pinfo'
202 arg = " ".join([method, target])
202 arg = " ".join([method, target])
203 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
203 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
204 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
204 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
205 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
205 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
206 if next_input is None:
206 if next_input is None:
207 return '%sget_ipython().run_line_magic(%r, %r)' % (lspace, t_magic_name, t_magic_arg_s)
207 return '%sget_ipython().run_line_magic(%r, %r)' % (lspace, t_magic_name, t_magic_arg_s)
208 else:
208 else:
209 return '%sget_ipython().set_next_input(%r);get_ipython().run_line_magic(%r, %r)' % \
209 return '%sget_ipython().set_next_input(%r);get_ipython().run_line_magic(%r, %r)' % \
210 (lspace, next_input, t_magic_name, t_magic_arg_s)
210 (lspace, next_input, t_magic_name, t_magic_arg_s)
211
211
212 # These define the transformations for the different escape characters.
212 # These define the transformations for the different escape characters.
213 def _tr_system(line_info):
213 def _tr_system(line_info):
214 "Translate lines escaped with: !"
214 "Translate lines escaped with: !"
215 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
215 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
216 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
216 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
217
217
218 def _tr_system2(line_info):
218 def _tr_system2(line_info):
219 "Translate lines escaped with: !!"
219 "Translate lines escaped with: !!"
220 cmd = line_info.line.lstrip()[2:]
220 cmd = line_info.line.lstrip()[2:]
221 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
221 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
222
222
223 def _tr_help(line_info):
223 def _tr_help(line_info):
224 "Translate lines escaped with: ?/??"
224 "Translate lines escaped with: ?/??"
225 # A naked help line should just fire the intro help screen
225 # A naked help line should just fire the intro help screen
226 if not line_info.line[1:]:
226 if not line_info.line[1:]:
227 return 'get_ipython().show_usage()'
227 return 'get_ipython().show_usage()'
228
228
229 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
229 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
230
230
231 def _tr_magic(line_info):
231 def _tr_magic(line_info):
232 "Translate lines escaped with: %"
232 "Translate lines escaped with: %"
233 tpl = '%sget_ipython().run_line_magic(%r, %r)'
233 tpl = '%sget_ipython().run_line_magic(%r, %r)'
234 if line_info.line.startswith(ESC_MAGIC2):
234 if line_info.line.startswith(ESC_MAGIC2):
235 return line_info.line
235 return line_info.line
236 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
236 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
237 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
237 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
238 t_magic_name, _, t_magic_arg_s = cmd.partition(' ')
238 t_magic_name, _, t_magic_arg_s = cmd.partition(' ')
239 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
239 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
240 return tpl % (line_info.pre, t_magic_name, t_magic_arg_s)
240 return tpl % (line_info.pre, t_magic_name, t_magic_arg_s)
241
241
242 def _tr_quote(line_info):
242 def _tr_quote(line_info):
243 "Translate lines escaped with: ,"
243 "Translate lines escaped with: ,"
244 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
244 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
245 '", "'.join(line_info.the_rest.split()) )
245 '", "'.join(line_info.the_rest.split()) )
246
246
247 def _tr_quote2(line_info):
247 def _tr_quote2(line_info):
248 "Translate lines escaped with: ;"
248 "Translate lines escaped with: ;"
249 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
249 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
250 line_info.the_rest)
250 line_info.the_rest)
251
251
252 def _tr_paren(line_info):
252 def _tr_paren(line_info):
253 "Translate lines escaped with: /"
253 "Translate lines escaped with: /"
254 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
254 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
255 ", ".join(line_info.the_rest.split()))
255 ", ".join(line_info.the_rest.split()))
256
256
257 tr = { ESC_SHELL : _tr_system,
257 tr = { ESC_SHELL : _tr_system,
258 ESC_SH_CAP : _tr_system2,
258 ESC_SH_CAP : _tr_system2,
259 ESC_HELP : _tr_help,
259 ESC_HELP : _tr_help,
260 ESC_HELP2 : _tr_help,
260 ESC_HELP2 : _tr_help,
261 ESC_MAGIC : _tr_magic,
261 ESC_MAGIC : _tr_magic,
262 ESC_QUOTE : _tr_quote,
262 ESC_QUOTE : _tr_quote,
263 ESC_QUOTE2 : _tr_quote2,
263 ESC_QUOTE2 : _tr_quote2,
264 ESC_PAREN : _tr_paren }
264 ESC_PAREN : _tr_paren }
265
265
266 @StatelessInputTransformer.wrap
266 @StatelessInputTransformer.wrap
267 def escaped_commands(line):
267 def escaped_commands(line):
268 """Transform escaped commands - %magic, !system, ?help + various autocalls.
268 """Transform escaped commands - %magic, !system, ?help + various autocalls.
269 """
269 """
270 if not line or line.isspace():
270 if not line or line.isspace():
271 return line
271 return line
272 lineinf = LineInfo(line)
272 lineinf = LineInfo(line)
273 if lineinf.esc not in tr:
273 if lineinf.esc not in tr:
274 return line
274 return line
275
275
276 return tr[lineinf.esc](lineinf)
276 return tr[lineinf.esc](lineinf)
277
277
278 _initial_space_re = re.compile(r'\s*')
278 _initial_space_re = re.compile(r'\s*')
279
279
280 _help_end_re = re.compile(r"""(%{0,2}
280 _help_end_re = re.compile(r"""(%{0,2}
281 [a-zA-Z_*][\w*]* # Variable name
281 (?!\d)[\w*]+ # Variable name
282 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
282 (\.(?!\d)[\w*]+)* # .etc.etc
283 )
283 )
284 (\?\??)$ # ? or ??
284 (\?\??)$ # ? or ??
285 """,
285 """,
286 re.VERBOSE)
286 re.VERBOSE)
287
287
288 # Extra pseudotokens for multiline strings and data structures
288 # Extra pseudotokens for multiline strings and data structures
289 _MULTILINE_STRING = object()
289 _MULTILINE_STRING = object()
290 _MULTILINE_STRUCTURE = object()
290 _MULTILINE_STRUCTURE = object()
291
291
292 def _line_tokens(line):
292 def _line_tokens(line):
293 """Helper for has_comment and ends_in_comment_or_string."""
293 """Helper for has_comment and ends_in_comment_or_string."""
294 readline = StringIO(line).readline
294 readline = StringIO(line).readline
295 toktypes = set()
295 toktypes = set()
296 try:
296 try:
297 for t in generate_tokens(readline):
297 for t in generate_tokens(readline):
298 toktypes.add(t[0])
298 toktypes.add(t[0])
299 except TokenError as e:
299 except TokenError as e:
300 # There are only two cases where a TokenError is raised.
300 # There are only two cases where a TokenError is raised.
301 if 'multi-line string' in e.args[0]:
301 if 'multi-line string' in e.args[0]:
302 toktypes.add(_MULTILINE_STRING)
302 toktypes.add(_MULTILINE_STRING)
303 else:
303 else:
304 toktypes.add(_MULTILINE_STRUCTURE)
304 toktypes.add(_MULTILINE_STRUCTURE)
305 return toktypes
305 return toktypes
306
306
307 def has_comment(src):
307 def has_comment(src):
308 """Indicate whether an input line has (i.e. ends in, or is) a comment.
308 """Indicate whether an input line has (i.e. ends in, or is) a comment.
309
309
310 This uses tokenize, so it can distinguish comments from # inside strings.
310 This uses tokenize, so it can distinguish comments from # inside strings.
311
311
312 Parameters
312 Parameters
313 ----------
313 ----------
314 src : string
314 src : string
315 A single line input string.
315 A single line input string.
316
316
317 Returns
317 Returns
318 -------
318 -------
319 comment : bool
319 comment : bool
320 True if source has a comment.
320 True if source has a comment.
321 """
321 """
322 return (tokenize.COMMENT in _line_tokens(src))
322 return (tokenize.COMMENT in _line_tokens(src))
323
323
324 def ends_in_comment_or_string(src):
324 def ends_in_comment_or_string(src):
325 """Indicates whether or not an input line ends in a comment or within
325 """Indicates whether or not an input line ends in a comment or within
326 a multiline string.
326 a multiline string.
327
327
328 Parameters
328 Parameters
329 ----------
329 ----------
330 src : string
330 src : string
331 A single line input string.
331 A single line input string.
332
332
333 Returns
333 Returns
334 -------
334 -------
335 comment : bool
335 comment : bool
336 True if source ends in a comment or multiline string.
336 True if source ends in a comment or multiline string.
337 """
337 """
338 toktypes = _line_tokens(src)
338 toktypes = _line_tokens(src)
339 return (tokenize.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
339 return (tokenize.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
340
340
341
341
342 @StatelessInputTransformer.wrap
342 @StatelessInputTransformer.wrap
343 def help_end(line):
343 def help_end(line):
344 """Translate lines with ?/?? at the end"""
344 """Translate lines with ?/?? at the end"""
345 m = _help_end_re.search(line)
345 m = _help_end_re.search(line)
346 if m is None or ends_in_comment_or_string(line):
346 if m is None or ends_in_comment_or_string(line):
347 return line
347 return line
348 target = m.group(1)
348 target = m.group(1)
349 esc = m.group(3)
349 esc = m.group(3)
350 lspace = _initial_space_re.match(line).group(0)
350 lspace = _initial_space_re.match(line).group(0)
351
351
352 # If we're mid-command, put it back on the next prompt for the user.
352 # If we're mid-command, put it back on the next prompt for the user.
353 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
353 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
354
354
355 return _make_help_call(target, esc, lspace, next_input)
355 return _make_help_call(target, esc, lspace, next_input)
356
356
357
357
358 @CoroutineInputTransformer.wrap
358 @CoroutineInputTransformer.wrap
359 def cellmagic(end_on_blank_line=False):
359 def cellmagic(end_on_blank_line=False):
360 """Captures & transforms cell magics.
360 """Captures & transforms cell magics.
361
361
362 After a cell magic is started, this stores up any lines it gets until it is
362 After a cell magic is started, this stores up any lines it gets until it is
363 reset (sent None).
363 reset (sent None).
364 """
364 """
365 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
365 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
366 cellmagic_help_re = re.compile(r'%%\w+\?')
366 cellmagic_help_re = re.compile(r'%%\w+\?')
367 line = ''
367 line = ''
368 while True:
368 while True:
369 line = (yield line)
369 line = (yield line)
370 # consume leading empty lines
370 # consume leading empty lines
371 while not line:
371 while not line:
372 line = (yield line)
372 line = (yield line)
373
373
374 if not line.startswith(ESC_MAGIC2):
374 if not line.startswith(ESC_MAGIC2):
375 # This isn't a cell magic, idle waiting for reset then start over
375 # This isn't a cell magic, idle waiting for reset then start over
376 while line is not None:
376 while line is not None:
377 line = (yield line)
377 line = (yield line)
378 continue
378 continue
379
379
380 if cellmagic_help_re.match(line):
380 if cellmagic_help_re.match(line):
381 # This case will be handled by help_end
381 # This case will be handled by help_end
382 continue
382 continue
383
383
384 first = line
384 first = line
385 body = []
385 body = []
386 line = (yield None)
386 line = (yield None)
387 while (line is not None) and \
387 while (line is not None) and \
388 ((line.strip() != '') or not end_on_blank_line):
388 ((line.strip() != '') or not end_on_blank_line):
389 body.append(line)
389 body.append(line)
390 line = (yield None)
390 line = (yield None)
391
391
392 # Output
392 # Output
393 magic_name, _, first = first.partition(' ')
393 magic_name, _, first = first.partition(' ')
394 magic_name = magic_name.lstrip(ESC_MAGIC2)
394 magic_name = magic_name.lstrip(ESC_MAGIC2)
395 line = tpl % (magic_name, first, u'\n'.join(body))
395 line = tpl % (magic_name, first, u'\n'.join(body))
396
396
397
397
398 def _strip_prompts(prompt_re, initial_re=None, turnoff_re=None):
398 def _strip_prompts(prompt_re, initial_re=None, turnoff_re=None):
399 """Remove matching input prompts from a block of input.
399 """Remove matching input prompts from a block of input.
400
400
401 Parameters
401 Parameters
402 ----------
402 ----------
403 prompt_re : regular expression
403 prompt_re : regular expression
404 A regular expression matching any input prompt (including continuation)
404 A regular expression matching any input prompt (including continuation)
405 initial_re : regular expression, optional
405 initial_re : regular expression, optional
406 A regular expression matching only the initial prompt, but not continuation.
406 A regular expression matching only the initial prompt, but not continuation.
407 If no initial expression is given, prompt_re will be used everywhere.
407 If no initial expression is given, prompt_re will be used everywhere.
408 Used mainly for plain Python prompts, where the continuation prompt
408 Used mainly for plain Python prompts, where the continuation prompt
409 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
409 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
410
410
411 If initial_re and prompt_re differ,
411 If initial_re and prompt_re differ,
412 only initial_re will be tested against the first line.
412 only initial_re will be tested against the first line.
413 If any prompt is found on the first two lines,
413 If any prompt is found on the first two lines,
414 prompts will be stripped from the rest of the block.
414 prompts will be stripped from the rest of the block.
415 """
415 """
416 if initial_re is None:
416 if initial_re is None:
417 initial_re = prompt_re
417 initial_re = prompt_re
418 line = ''
418 line = ''
419 while True:
419 while True:
420 line = (yield line)
420 line = (yield line)
421
421
422 # First line of cell
422 # First line of cell
423 if line is None:
423 if line is None:
424 continue
424 continue
425 out, n1 = initial_re.subn('', line, count=1)
425 out, n1 = initial_re.subn('', line, count=1)
426 if turnoff_re and not n1:
426 if turnoff_re and not n1:
427 if turnoff_re.match(line):
427 if turnoff_re.match(line):
428 # We're in e.g. a cell magic; disable this transformer for
428 # We're in e.g. a cell magic; disable this transformer for
429 # the rest of the cell.
429 # the rest of the cell.
430 while line is not None:
430 while line is not None:
431 line = (yield line)
431 line = (yield line)
432 continue
432 continue
433
433
434 line = (yield out)
434 line = (yield out)
435
435
436 if line is None:
436 if line is None:
437 continue
437 continue
438 # check for any prompt on the second line of the cell,
438 # check for any prompt on the second line of the cell,
439 # because people often copy from just after the first prompt,
439 # because people often copy from just after the first prompt,
440 # so we might not see it in the first line.
440 # so we might not see it in the first line.
441 out, n2 = prompt_re.subn('', line, count=1)
441 out, n2 = prompt_re.subn('', line, count=1)
442 line = (yield out)
442 line = (yield out)
443
443
444 if n1 or n2:
444 if n1 or n2:
445 # Found a prompt in the first two lines - check for it in
445 # Found a prompt in the first two lines - check for it in
446 # the rest of the cell as well.
446 # the rest of the cell as well.
447 while line is not None:
447 while line is not None:
448 line = (yield prompt_re.sub('', line, count=1))
448 line = (yield prompt_re.sub('', line, count=1))
449
449
450 else:
450 else:
451 # Prompts not in input - wait for reset
451 # Prompts not in input - wait for reset
452 while line is not None:
452 while line is not None:
453 line = (yield line)
453 line = (yield line)
454
454
455 @CoroutineInputTransformer.wrap
455 @CoroutineInputTransformer.wrap
456 def classic_prompt():
456 def classic_prompt():
457 """Strip the >>>/... prompts of the Python interactive shell."""
457 """Strip the >>>/... prompts of the Python interactive shell."""
458 # FIXME: non-capturing version (?:...) usable?
458 # FIXME: non-capturing version (?:...) usable?
459 prompt_re = re.compile(r'^(>>>|\.\.\.)( |$)')
459 prompt_re = re.compile(r'^(>>>|\.\.\.)( |$)')
460 initial_re = re.compile(r'^>>>( |$)')
460 initial_re = re.compile(r'^>>>( |$)')
461 # Any %magic/!system is IPython syntax, so we needn't look for >>> prompts
461 # Any %magic/!system is IPython syntax, so we needn't look for >>> prompts
462 turnoff_re = re.compile(r'^[%!]')
462 turnoff_re = re.compile(r'^[%!]')
463 return _strip_prompts(prompt_re, initial_re, turnoff_re)
463 return _strip_prompts(prompt_re, initial_re, turnoff_re)
464
464
465 @CoroutineInputTransformer.wrap
465 @CoroutineInputTransformer.wrap
466 def ipy_prompt():
466 def ipy_prompt():
467 """Strip IPython's In [1]:/...: prompts."""
467 """Strip IPython's In [1]:/...: prompts."""
468 # FIXME: non-capturing version (?:...) usable?
468 # FIXME: non-capturing version (?:...) usable?
469 prompt_re = re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)')
469 prompt_re = re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)')
470 # Disable prompt stripping inside cell magics
470 # Disable prompt stripping inside cell magics
471 turnoff_re = re.compile(r'^%%')
471 turnoff_re = re.compile(r'^%%')
472 return _strip_prompts(prompt_re, turnoff_re=turnoff_re)
472 return _strip_prompts(prompt_re, turnoff_re=turnoff_re)
473
473
474
474
475 @CoroutineInputTransformer.wrap
475 @CoroutineInputTransformer.wrap
476 def leading_indent():
476 def leading_indent():
477 """Remove leading indentation.
477 """Remove leading indentation.
478
478
479 If the first line starts with a spaces or tabs, the same whitespace will be
479 If the first line starts with a spaces or tabs, the same whitespace will be
480 removed from each following line until it is reset.
480 removed from each following line until it is reset.
481 """
481 """
482 space_re = re.compile(r'^[ \t]+')
482 space_re = re.compile(r'^[ \t]+')
483 line = ''
483 line = ''
484 while True:
484 while True:
485 line = (yield line)
485 line = (yield line)
486
486
487 if line is None:
487 if line is None:
488 continue
488 continue
489
489
490 m = space_re.match(line)
490 m = space_re.match(line)
491 if m:
491 if m:
492 space = m.group(0)
492 space = m.group(0)
493 while line is not None:
493 while line is not None:
494 if line.startswith(space):
494 if line.startswith(space):
495 line = line[len(space):]
495 line = line[len(space):]
496 line = (yield line)
496 line = (yield line)
497 else:
497 else:
498 # No leading spaces - wait for reset
498 # No leading spaces - wait for reset
499 while line is not None:
499 while line is not None:
500 line = (yield line)
500 line = (yield line)
501
501
502
502
503 _assign_pat = \
503 _assign_pat = \
504 r'''(?P<lhs>(\s*)
504 r'''(?P<lhs>(\s*)
505 ([\w\.]+) # Initial identifier
505 ([\w\.]+) # Initial identifier
506 (\s*,\s*
506 (\s*,\s*
507 \*?[\w\.]+)* # Further identifiers for unpacking
507 \*?[\w\.]+)* # Further identifiers for unpacking
508 \s*?,? # Trailing comma
508 \s*?,? # Trailing comma
509 )
509 )
510 \s*=\s*
510 \s*=\s*
511 '''
511 '''
512
512
513 assign_system_re = re.compile(r'{}!\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
513 assign_system_re = re.compile(r'{}!\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
514 assign_system_template = '%s = get_ipython().getoutput(%r)'
514 assign_system_template = '%s = get_ipython().getoutput(%r)'
515 @StatelessInputTransformer.wrap
515 @StatelessInputTransformer.wrap
516 def assign_from_system(line):
516 def assign_from_system(line):
517 """Transform assignment from system commands (e.g. files = !ls)"""
517 """Transform assignment from system commands (e.g. files = !ls)"""
518 m = assign_system_re.match(line)
518 m = assign_system_re.match(line)
519 if m is None:
519 if m is None:
520 return line
520 return line
521
521
522 return assign_system_template % m.group('lhs', 'cmd')
522 return assign_system_template % m.group('lhs', 'cmd')
523
523
524 assign_magic_re = re.compile(r'{}%\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
524 assign_magic_re = re.compile(r'{}%\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
525 assign_magic_template = '%s = get_ipython().run_line_magic(%r, %r)'
525 assign_magic_template = '%s = get_ipython().run_line_magic(%r, %r)'
526 @StatelessInputTransformer.wrap
526 @StatelessInputTransformer.wrap
527 def assign_from_magic(line):
527 def assign_from_magic(line):
528 """Transform assignment from magic commands (e.g. a = %who_ls)"""
528 """Transform assignment from magic commands (e.g. a = %who_ls)"""
529 m = assign_magic_re.match(line)
529 m = assign_magic_re.match(line)
530 if m is None:
530 if m is None:
531 return line
531 return line
532 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
532 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
533 m_lhs, m_cmd = m.group('lhs', 'cmd')
533 m_lhs, m_cmd = m.group('lhs', 'cmd')
534 t_magic_name, _, t_magic_arg_s = m_cmd.partition(' ')
534 t_magic_name, _, t_magic_arg_s = m_cmd.partition(' ')
535 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
535 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
536 return assign_magic_template % (m_lhs, t_magic_name, t_magic_arg_s)
536 return assign_magic_template % (m_lhs, t_magic_name, t_magic_arg_s)
@@ -1,721 +1,721 b''
1 """Input transformer machinery to support IPython special syntax.
1 """Input transformer machinery to support IPython special syntax.
2
2
3 This includes the machinery to recognise and transform ``%magic`` commands,
3 This includes the machinery to recognise and transform ``%magic`` commands,
4 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
4 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
5
5
6 Added: IPython 7.0. Replaces inputsplitter and inputtransformer which were
6 Added: IPython 7.0. Replaces inputsplitter and inputtransformer which were
7 deprecated in 7.0.
7 deprecated in 7.0.
8 """
8 """
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 from codeop import compile_command
13 from codeop import compile_command
14 import re
14 import re
15 import tokenize
15 import tokenize
16 from typing import List, Tuple, Union
16 from typing import List, Tuple, Union
17 import warnings
17 import warnings
18
18
19 _indent_re = re.compile(r'^[ \t]+')
19 _indent_re = re.compile(r'^[ \t]+')
20
20
21 def leading_empty_lines(lines):
21 def leading_empty_lines(lines):
22 """Remove leading empty lines
22 """Remove leading empty lines
23
23
24 If the leading lines are empty or contain only whitespace, they will be
24 If the leading lines are empty or contain only whitespace, they will be
25 removed.
25 removed.
26 """
26 """
27 if not lines:
27 if not lines:
28 return lines
28 return lines
29 for i, line in enumerate(lines):
29 for i, line in enumerate(lines):
30 if line and not line.isspace():
30 if line and not line.isspace():
31 return lines[i:]
31 return lines[i:]
32 return lines
32 return lines
33
33
34 def leading_indent(lines):
34 def leading_indent(lines):
35 """Remove leading indentation.
35 """Remove leading indentation.
36
36
37 If the first line starts with a spaces or tabs, the same whitespace will be
37 If the first line starts with a spaces or tabs, the same whitespace will be
38 removed from each following line in the cell.
38 removed from each following line in the cell.
39 """
39 """
40 if not lines:
40 if not lines:
41 return lines
41 return lines
42 m = _indent_re.match(lines[0])
42 m = _indent_re.match(lines[0])
43 if not m:
43 if not m:
44 return lines
44 return lines
45 space = m.group(0)
45 space = m.group(0)
46 n = len(space)
46 n = len(space)
47 return [l[n:] if l.startswith(space) else l
47 return [l[n:] if l.startswith(space) else l
48 for l in lines]
48 for l in lines]
49
49
50 class PromptStripper:
50 class PromptStripper:
51 """Remove matching input prompts from a block of input.
51 """Remove matching input prompts from a block of input.
52
52
53 Parameters
53 Parameters
54 ----------
54 ----------
55 prompt_re : regular expression
55 prompt_re : regular expression
56 A regular expression matching any input prompt (including continuation,
56 A regular expression matching any input prompt (including continuation,
57 e.g. ``...``)
57 e.g. ``...``)
58 initial_re : regular expression, optional
58 initial_re : regular expression, optional
59 A regular expression matching only the initial prompt, but not continuation.
59 A regular expression matching only the initial prompt, but not continuation.
60 If no initial expression is given, prompt_re will be used everywhere.
60 If no initial expression is given, prompt_re will be used everywhere.
61 Used mainly for plain Python prompts (``>>>``), where the continuation prompt
61 Used mainly for plain Python prompts (``>>>``), where the continuation prompt
62 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
62 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
63
63
64 If initial_re and prompt_re differ,
64 If initial_re and prompt_re differ,
65 only initial_re will be tested against the first line.
65 only initial_re will be tested against the first line.
66 If any prompt is found on the first two lines,
66 If any prompt is found on the first two lines,
67 prompts will be stripped from the rest of the block.
67 prompts will be stripped from the rest of the block.
68 """
68 """
69 def __init__(self, prompt_re, initial_re=None):
69 def __init__(self, prompt_re, initial_re=None):
70 self.prompt_re = prompt_re
70 self.prompt_re = prompt_re
71 self.initial_re = initial_re or prompt_re
71 self.initial_re = initial_re or prompt_re
72
72
73 def _strip(self, lines):
73 def _strip(self, lines):
74 return [self.prompt_re.sub('', l, count=1) for l in lines]
74 return [self.prompt_re.sub('', l, count=1) for l in lines]
75
75
76 def __call__(self, lines):
76 def __call__(self, lines):
77 if not lines:
77 if not lines:
78 return lines
78 return lines
79 if self.initial_re.match(lines[0]) or \
79 if self.initial_re.match(lines[0]) or \
80 (len(lines) > 1 and self.prompt_re.match(lines[1])):
80 (len(lines) > 1 and self.prompt_re.match(lines[1])):
81 return self._strip(lines)
81 return self._strip(lines)
82 return lines
82 return lines
83
83
84 classic_prompt = PromptStripper(
84 classic_prompt = PromptStripper(
85 prompt_re=re.compile(r'^(>>>|\.\.\.)( |$)'),
85 prompt_re=re.compile(r'^(>>>|\.\.\.)( |$)'),
86 initial_re=re.compile(r'^>>>( |$)')
86 initial_re=re.compile(r'^>>>( |$)')
87 )
87 )
88
88
89 ipython_prompt = PromptStripper(re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)'))
89 ipython_prompt = PromptStripper(re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)'))
90
90
91 def cell_magic(lines):
91 def cell_magic(lines):
92 if not lines or not lines[0].startswith('%%'):
92 if not lines or not lines[0].startswith('%%'):
93 return lines
93 return lines
94 if re.match(r'%%\w+\?', lines[0]):
94 if re.match(r'%%\w+\?', lines[0]):
95 # This case will be handled by help_end
95 # This case will be handled by help_end
96 return lines
96 return lines
97 magic_name, _, first_line = lines[0][2:-1].partition(' ')
97 magic_name, _, first_line = lines[0][2:-1].partition(' ')
98 body = ''.join(lines[1:])
98 body = ''.join(lines[1:])
99 return ['get_ipython().run_cell_magic(%r, %r, %r)\n'
99 return ['get_ipython().run_cell_magic(%r, %r, %r)\n'
100 % (magic_name, first_line, body)]
100 % (magic_name, first_line, body)]
101
101
102
102
103 def _find_assign_op(token_line) -> Union[int, None]:
103 def _find_assign_op(token_line) -> Union[int, None]:
104 """Get the index of the first assignment in the line ('=' not inside brackets)
104 """Get the index of the first assignment in the line ('=' not inside brackets)
105
105
106 Note: We don't try to support multiple special assignment (a = b = %foo)
106 Note: We don't try to support multiple special assignment (a = b = %foo)
107 """
107 """
108 paren_level = 0
108 paren_level = 0
109 for i, ti in enumerate(token_line):
109 for i, ti in enumerate(token_line):
110 s = ti.string
110 s = ti.string
111 if s == '=' and paren_level == 0:
111 if s == '=' and paren_level == 0:
112 return i
112 return i
113 if s in {'(','[','{'}:
113 if s in {'(','[','{'}:
114 paren_level += 1
114 paren_level += 1
115 elif s in {')', ']', '}'}:
115 elif s in {')', ']', '}'}:
116 if paren_level > 0:
116 if paren_level > 0:
117 paren_level -= 1
117 paren_level -= 1
118
118
119 def find_end_of_continued_line(lines, start_line: int):
119 def find_end_of_continued_line(lines, start_line: int):
120 """Find the last line of a line explicitly extended using backslashes.
120 """Find the last line of a line explicitly extended using backslashes.
121
121
122 Uses 0-indexed line numbers.
122 Uses 0-indexed line numbers.
123 """
123 """
124 end_line = start_line
124 end_line = start_line
125 while lines[end_line].endswith('\\\n'):
125 while lines[end_line].endswith('\\\n'):
126 end_line += 1
126 end_line += 1
127 if end_line >= len(lines):
127 if end_line >= len(lines):
128 break
128 break
129 return end_line
129 return end_line
130
130
131 def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
131 def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
132 r"""Assemble a single line from multiple continued line pieces
132 r"""Assemble a single line from multiple continued line pieces
133
133
134 Continued lines are lines ending in ``\``, and the line following the last
134 Continued lines are lines ending in ``\``, and the line following the last
135 ``\`` in the block.
135 ``\`` in the block.
136
136
137 For example, this code continues over multiple lines::
137 For example, this code continues over multiple lines::
138
138
139 if (assign_ix is not None) \
139 if (assign_ix is not None) \
140 and (len(line) >= assign_ix + 2) \
140 and (len(line) >= assign_ix + 2) \
141 and (line[assign_ix+1].string == '%') \
141 and (line[assign_ix+1].string == '%') \
142 and (line[assign_ix+2].type == tokenize.NAME):
142 and (line[assign_ix+2].type == tokenize.NAME):
143
143
144 This statement contains four continued line pieces.
144 This statement contains four continued line pieces.
145 Assembling these pieces into a single line would give::
145 Assembling these pieces into a single line would give::
146
146
147 if (assign_ix is not None) and (len(line) >= assign_ix + 2) and (line[...
147 if (assign_ix is not None) and (len(line) >= assign_ix + 2) and (line[...
148
148
149 This uses 0-indexed line numbers. *start* is (lineno, colno).
149 This uses 0-indexed line numbers. *start* is (lineno, colno).
150
150
151 Used to allow ``%magic`` and ``!system`` commands to be continued over
151 Used to allow ``%magic`` and ``!system`` commands to be continued over
152 multiple lines.
152 multiple lines.
153 """
153 """
154 parts = [lines[start[0]][start[1]:]] + lines[start[0]+1:end_line+1]
154 parts = [lines[start[0]][start[1]:]] + lines[start[0]+1:end_line+1]
155 return ' '.join([p[:-2] for p in parts[:-1]] # Strip backslash+newline
155 return ' '.join([p[:-2] for p in parts[:-1]] # Strip backslash+newline
156 + [parts[-1][:-1]]) # Strip newline from last line
156 + [parts[-1][:-1]]) # Strip newline from last line
157
157
158 class TokenTransformBase:
158 class TokenTransformBase:
159 """Base class for transformations which examine tokens.
159 """Base class for transformations which examine tokens.
160
160
161 Special syntax should not be transformed when it occurs inside strings or
161 Special syntax should not be transformed when it occurs inside strings or
162 comments. This is hard to reliably avoid with regexes. The solution is to
162 comments. This is hard to reliably avoid with regexes. The solution is to
163 tokenise the code as Python, and recognise the special syntax in the tokens.
163 tokenise the code as Python, and recognise the special syntax in the tokens.
164
164
165 IPython's special syntax is not valid Python syntax, so tokenising may go
165 IPython's special syntax is not valid Python syntax, so tokenising may go
166 wrong after the special syntax starts. These classes therefore find and
166 wrong after the special syntax starts. These classes therefore find and
167 transform *one* instance of special syntax at a time into regular Python
167 transform *one* instance of special syntax at a time into regular Python
168 syntax. After each transformation, tokens are regenerated to find the next
168 syntax. After each transformation, tokens are regenerated to find the next
169 piece of special syntax.
169 piece of special syntax.
170
170
171 Subclasses need to implement one class method (find)
171 Subclasses need to implement one class method (find)
172 and one regular method (transform).
172 and one regular method (transform).
173
173
174 The priority attribute can select which transformation to apply if multiple
174 The priority attribute can select which transformation to apply if multiple
175 transformers match in the same place. Lower numbers have higher priority.
175 transformers match in the same place. Lower numbers have higher priority.
176 This allows "%magic?" to be turned into a help call rather than a magic call.
176 This allows "%magic?" to be turned into a help call rather than a magic call.
177 """
177 """
178 # Lower numbers -> higher priority (for matches in the same location)
178 # Lower numbers -> higher priority (for matches in the same location)
179 priority = 10
179 priority = 10
180
180
181 def sortby(self):
181 def sortby(self):
182 return self.start_line, self.start_col, self.priority
182 return self.start_line, self.start_col, self.priority
183
183
184 def __init__(self, start):
184 def __init__(self, start):
185 self.start_line = start[0] - 1 # Shift from 1-index to 0-index
185 self.start_line = start[0] - 1 # Shift from 1-index to 0-index
186 self.start_col = start[1]
186 self.start_col = start[1]
187
187
188 @classmethod
188 @classmethod
189 def find(cls, tokens_by_line):
189 def find(cls, tokens_by_line):
190 """Find one instance of special syntax in the provided tokens.
190 """Find one instance of special syntax in the provided tokens.
191
191
192 Tokens are grouped into logical lines for convenience,
192 Tokens are grouped into logical lines for convenience,
193 so it is easy to e.g. look at the first token of each line.
193 so it is easy to e.g. look at the first token of each line.
194 *tokens_by_line* is a list of lists of tokenize.TokenInfo objects.
194 *tokens_by_line* is a list of lists of tokenize.TokenInfo objects.
195
195
196 This should return an instance of its class, pointing to the start
196 This should return an instance of its class, pointing to the start
197 position it has found, or None if it found no match.
197 position it has found, or None if it found no match.
198 """
198 """
199 raise NotImplementedError
199 raise NotImplementedError
200
200
201 def transform(self, lines: List[str]):
201 def transform(self, lines: List[str]):
202 """Transform one instance of special syntax found by ``find()``
202 """Transform one instance of special syntax found by ``find()``
203
203
204 Takes a list of strings representing physical lines,
204 Takes a list of strings representing physical lines,
205 returns a similar list of transformed lines.
205 returns a similar list of transformed lines.
206 """
206 """
207 raise NotImplementedError
207 raise NotImplementedError
208
208
209 class MagicAssign(TokenTransformBase):
209 class MagicAssign(TokenTransformBase):
210 """Transformer for assignments from magics (a = %foo)"""
210 """Transformer for assignments from magics (a = %foo)"""
211 @classmethod
211 @classmethod
212 def find(cls, tokens_by_line):
212 def find(cls, tokens_by_line):
213 """Find the first magic assignment (a = %foo) in the cell.
213 """Find the first magic assignment (a = %foo) in the cell.
214 """
214 """
215 for line in tokens_by_line:
215 for line in tokens_by_line:
216 assign_ix = _find_assign_op(line)
216 assign_ix = _find_assign_op(line)
217 if (assign_ix is not None) \
217 if (assign_ix is not None) \
218 and (len(line) >= assign_ix + 2) \
218 and (len(line) >= assign_ix + 2) \
219 and (line[assign_ix+1].string == '%') \
219 and (line[assign_ix+1].string == '%') \
220 and (line[assign_ix+2].type == tokenize.NAME):
220 and (line[assign_ix+2].type == tokenize.NAME):
221 return cls(line[assign_ix+1].start)
221 return cls(line[assign_ix+1].start)
222
222
223 def transform(self, lines: List[str]):
223 def transform(self, lines: List[str]):
224 """Transform a magic assignment found by the ``find()`` classmethod.
224 """Transform a magic assignment found by the ``find()`` classmethod.
225 """
225 """
226 start_line, start_col = self.start_line, self.start_col
226 start_line, start_col = self.start_line, self.start_col
227 lhs = lines[start_line][:start_col]
227 lhs = lines[start_line][:start_col]
228 end_line = find_end_of_continued_line(lines, start_line)
228 end_line = find_end_of_continued_line(lines, start_line)
229 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
229 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
230 assert rhs.startswith('%'), rhs
230 assert rhs.startswith('%'), rhs
231 magic_name, _, args = rhs[1:].partition(' ')
231 magic_name, _, args = rhs[1:].partition(' ')
232
232
233 lines_before = lines[:start_line]
233 lines_before = lines[:start_line]
234 call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
234 call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
235 new_line = lhs + call + '\n'
235 new_line = lhs + call + '\n'
236 lines_after = lines[end_line+1:]
236 lines_after = lines[end_line+1:]
237
237
238 return lines_before + [new_line] + lines_after
238 return lines_before + [new_line] + lines_after
239
239
240
240
241 class SystemAssign(TokenTransformBase):
241 class SystemAssign(TokenTransformBase):
242 """Transformer for assignments from system commands (a = !foo)"""
242 """Transformer for assignments from system commands (a = !foo)"""
243 @classmethod
243 @classmethod
244 def find(cls, tokens_by_line):
244 def find(cls, tokens_by_line):
245 """Find the first system assignment (a = !foo) in the cell.
245 """Find the first system assignment (a = !foo) in the cell.
246 """
246 """
247 for line in tokens_by_line:
247 for line in tokens_by_line:
248 assign_ix = _find_assign_op(line)
248 assign_ix = _find_assign_op(line)
249 if (assign_ix is not None) \
249 if (assign_ix is not None) \
250 and not line[assign_ix].line.strip().startswith('=') \
250 and not line[assign_ix].line.strip().startswith('=') \
251 and (len(line) >= assign_ix + 2) \
251 and (len(line) >= assign_ix + 2) \
252 and (line[assign_ix + 1].type == tokenize.ERRORTOKEN):
252 and (line[assign_ix + 1].type == tokenize.ERRORTOKEN):
253 ix = assign_ix + 1
253 ix = assign_ix + 1
254
254
255 while ix < len(line) and line[ix].type == tokenize.ERRORTOKEN:
255 while ix < len(line) and line[ix].type == tokenize.ERRORTOKEN:
256 if line[ix].string == '!':
256 if line[ix].string == '!':
257 return cls(line[ix].start)
257 return cls(line[ix].start)
258 elif not line[ix].string.isspace():
258 elif not line[ix].string.isspace():
259 break
259 break
260 ix += 1
260 ix += 1
261
261
262 def transform(self, lines: List[str]):
262 def transform(self, lines: List[str]):
263 """Transform a system assignment found by the ``find()`` classmethod.
263 """Transform a system assignment found by the ``find()`` classmethod.
264 """
264 """
265 start_line, start_col = self.start_line, self.start_col
265 start_line, start_col = self.start_line, self.start_col
266
266
267 lhs = lines[start_line][:start_col]
267 lhs = lines[start_line][:start_col]
268 end_line = find_end_of_continued_line(lines, start_line)
268 end_line = find_end_of_continued_line(lines, start_line)
269 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
269 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
270 assert rhs.startswith('!'), rhs
270 assert rhs.startswith('!'), rhs
271 cmd = rhs[1:]
271 cmd = rhs[1:]
272
272
273 lines_before = lines[:start_line]
273 lines_before = lines[:start_line]
274 call = "get_ipython().getoutput({!r})".format(cmd)
274 call = "get_ipython().getoutput({!r})".format(cmd)
275 new_line = lhs + call + '\n'
275 new_line = lhs + call + '\n'
276 lines_after = lines[end_line + 1:]
276 lines_after = lines[end_line + 1:]
277
277
278 return lines_before + [new_line] + lines_after
278 return lines_before + [new_line] + lines_after
279
279
280 # The escape sequences that define the syntax transformations IPython will
280 # The escape sequences that define the syntax transformations IPython will
281 # apply to user input. These can NOT be just changed here: many regular
281 # apply to user input. These can NOT be just changed here: many regular
282 # expressions and other parts of the code may use their hardcoded values, and
282 # expressions and other parts of the code may use their hardcoded values, and
283 # for all intents and purposes they constitute the 'IPython syntax', so they
283 # for all intents and purposes they constitute the 'IPython syntax', so they
284 # should be considered fixed.
284 # should be considered fixed.
285
285
286 ESC_SHELL = '!' # Send line to underlying system shell
286 ESC_SHELL = '!' # Send line to underlying system shell
287 ESC_SH_CAP = '!!' # Send line to system shell and capture output
287 ESC_SH_CAP = '!!' # Send line to system shell and capture output
288 ESC_HELP = '?' # Find information about object
288 ESC_HELP = '?' # Find information about object
289 ESC_HELP2 = '??' # Find extra-detailed information about object
289 ESC_HELP2 = '??' # Find extra-detailed information about object
290 ESC_MAGIC = '%' # Call magic function
290 ESC_MAGIC = '%' # Call magic function
291 ESC_MAGIC2 = '%%' # Call cell-magic function
291 ESC_MAGIC2 = '%%' # Call cell-magic function
292 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
292 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
293 ESC_QUOTE2 = ';' # Quote all args as a single string, call
293 ESC_QUOTE2 = ';' # Quote all args as a single string, call
294 ESC_PAREN = '/' # Call first argument with rest of line as arguments
294 ESC_PAREN = '/' # Call first argument with rest of line as arguments
295
295
296 ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
296 ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
297 ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
297 ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
298
298
299 def _make_help_call(target, esc, next_input=None):
299 def _make_help_call(target, esc, next_input=None):
300 """Prepares a pinfo(2)/psearch call from a target name and the escape
300 """Prepares a pinfo(2)/psearch call from a target name and the escape
301 (i.e. ? or ??)"""
301 (i.e. ? or ??)"""
302 method = 'pinfo2' if esc == '??' \
302 method = 'pinfo2' if esc == '??' \
303 else 'psearch' if '*' in target \
303 else 'psearch' if '*' in target \
304 else 'pinfo'
304 else 'pinfo'
305 arg = " ".join([method, target])
305 arg = " ".join([method, target])
306 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
306 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
307 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
307 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
308 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
308 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
309 if next_input is None:
309 if next_input is None:
310 return 'get_ipython().run_line_magic(%r, %r)' % (t_magic_name, t_magic_arg_s)
310 return 'get_ipython().run_line_magic(%r, %r)' % (t_magic_name, t_magic_arg_s)
311 else:
311 else:
312 return 'get_ipython().set_next_input(%r);get_ipython().run_line_magic(%r, %r)' % \
312 return 'get_ipython().set_next_input(%r);get_ipython().run_line_magic(%r, %r)' % \
313 (next_input, t_magic_name, t_magic_arg_s)
313 (next_input, t_magic_name, t_magic_arg_s)
314
314
315 def _tr_help(content):
315 def _tr_help(content):
316 """Translate lines escaped with: ?
316 """Translate lines escaped with: ?
317
317
318 A naked help line should fire the intro help screen (shell.show_usage())
318 A naked help line should fire the intro help screen (shell.show_usage())
319 """
319 """
320 if not content:
320 if not content:
321 return 'get_ipython().show_usage()'
321 return 'get_ipython().show_usage()'
322
322
323 return _make_help_call(content, '?')
323 return _make_help_call(content, '?')
324
324
325 def _tr_help2(content):
325 def _tr_help2(content):
326 """Translate lines escaped with: ??
326 """Translate lines escaped with: ??
327
327
328 A naked help line should fire the intro help screen (shell.show_usage())
328 A naked help line should fire the intro help screen (shell.show_usage())
329 """
329 """
330 if not content:
330 if not content:
331 return 'get_ipython().show_usage()'
331 return 'get_ipython().show_usage()'
332
332
333 return _make_help_call(content, '??')
333 return _make_help_call(content, '??')
334
334
335 def _tr_magic(content):
335 def _tr_magic(content):
336 "Translate lines escaped with a percent sign: %"
336 "Translate lines escaped with a percent sign: %"
337 name, _, args = content.partition(' ')
337 name, _, args = content.partition(' ')
338 return 'get_ipython().run_line_magic(%r, %r)' % (name, args)
338 return 'get_ipython().run_line_magic(%r, %r)' % (name, args)
339
339
340 def _tr_quote(content):
340 def _tr_quote(content):
341 "Translate lines escaped with a comma: ,"
341 "Translate lines escaped with a comma: ,"
342 name, _, args = content.partition(' ')
342 name, _, args = content.partition(' ')
343 return '%s("%s")' % (name, '", "'.join(args.split()) )
343 return '%s("%s")' % (name, '", "'.join(args.split()) )
344
344
345 def _tr_quote2(content):
345 def _tr_quote2(content):
346 "Translate lines escaped with a semicolon: ;"
346 "Translate lines escaped with a semicolon: ;"
347 name, _, args = content.partition(' ')
347 name, _, args = content.partition(' ')
348 return '%s("%s")' % (name, args)
348 return '%s("%s")' % (name, args)
349
349
350 def _tr_paren(content):
350 def _tr_paren(content):
351 "Translate lines escaped with a slash: /"
351 "Translate lines escaped with a slash: /"
352 name, _, args = content.partition(' ')
352 name, _, args = content.partition(' ')
353 return '%s(%s)' % (name, ", ".join(args.split()))
353 return '%s(%s)' % (name, ", ".join(args.split()))
354
354
355 tr = { ESC_SHELL : 'get_ipython().system({!r})'.format,
355 tr = { ESC_SHELL : 'get_ipython().system({!r})'.format,
356 ESC_SH_CAP : 'get_ipython().getoutput({!r})'.format,
356 ESC_SH_CAP : 'get_ipython().getoutput({!r})'.format,
357 ESC_HELP : _tr_help,
357 ESC_HELP : _tr_help,
358 ESC_HELP2 : _tr_help2,
358 ESC_HELP2 : _tr_help2,
359 ESC_MAGIC : _tr_magic,
359 ESC_MAGIC : _tr_magic,
360 ESC_QUOTE : _tr_quote,
360 ESC_QUOTE : _tr_quote,
361 ESC_QUOTE2 : _tr_quote2,
361 ESC_QUOTE2 : _tr_quote2,
362 ESC_PAREN : _tr_paren }
362 ESC_PAREN : _tr_paren }
363
363
364 class EscapedCommand(TokenTransformBase):
364 class EscapedCommand(TokenTransformBase):
365 """Transformer for escaped commands like %foo, !foo, or /foo"""
365 """Transformer for escaped commands like %foo, !foo, or /foo"""
366 @classmethod
366 @classmethod
367 def find(cls, tokens_by_line):
367 def find(cls, tokens_by_line):
368 """Find the first escaped command (%foo, !foo, etc.) in the cell.
368 """Find the first escaped command (%foo, !foo, etc.) in the cell.
369 """
369 """
370 for line in tokens_by_line:
370 for line in tokens_by_line:
371 if not line:
371 if not line:
372 continue
372 continue
373 ix = 0
373 ix = 0
374 ll = len(line)
374 ll = len(line)
375 while ll > ix and line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
375 while ll > ix and line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
376 ix += 1
376 ix += 1
377 if ix >= ll:
377 if ix >= ll:
378 continue
378 continue
379 if line[ix].string in ESCAPE_SINGLES:
379 if line[ix].string in ESCAPE_SINGLES:
380 return cls(line[ix].start)
380 return cls(line[ix].start)
381
381
382 def transform(self, lines):
382 def transform(self, lines):
383 """Transform an escaped line found by the ``find()`` classmethod.
383 """Transform an escaped line found by the ``find()`` classmethod.
384 """
384 """
385 start_line, start_col = self.start_line, self.start_col
385 start_line, start_col = self.start_line, self.start_col
386
386
387 indent = lines[start_line][:start_col]
387 indent = lines[start_line][:start_col]
388 end_line = find_end_of_continued_line(lines, start_line)
388 end_line = find_end_of_continued_line(lines, start_line)
389 line = assemble_continued_line(lines, (start_line, start_col), end_line)
389 line = assemble_continued_line(lines, (start_line, start_col), end_line)
390
390
391 if len(line) > 1 and line[:2] in ESCAPE_DOUBLES:
391 if len(line) > 1 and line[:2] in ESCAPE_DOUBLES:
392 escape, content = line[:2], line[2:]
392 escape, content = line[:2], line[2:]
393 else:
393 else:
394 escape, content = line[:1], line[1:]
394 escape, content = line[:1], line[1:]
395
395
396 if escape in tr:
396 if escape in tr:
397 call = tr[escape](content)
397 call = tr[escape](content)
398 else:
398 else:
399 call = ''
399 call = ''
400
400
401 lines_before = lines[:start_line]
401 lines_before = lines[:start_line]
402 new_line = indent + call + '\n'
402 new_line = indent + call + '\n'
403 lines_after = lines[end_line + 1:]
403 lines_after = lines[end_line + 1:]
404
404
405 return lines_before + [new_line] + lines_after
405 return lines_before + [new_line] + lines_after
406
406
407 _help_end_re = re.compile(r"""(%{0,2}
407 _help_end_re = re.compile(r"""(%{0,2}
408 [a-zA-Z_*][\w*]* # Variable name
408 (?!\d)[\w*]+ # Variable name
409 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
409 (\.(?!\d)[\w*]+)* # .etc.etc
410 )
410 )
411 (\?\??)$ # ? or ??
411 (\?\??)$ # ? or ??
412 """,
412 """,
413 re.VERBOSE)
413 re.VERBOSE)
414
414
415 class HelpEnd(TokenTransformBase):
415 class HelpEnd(TokenTransformBase):
416 """Transformer for help syntax: obj? and obj??"""
416 """Transformer for help syntax: obj? and obj??"""
417 # This needs to be higher priority (lower number) than EscapedCommand so
417 # This needs to be higher priority (lower number) than EscapedCommand so
418 # that inspecting magics (%foo?) works.
418 # that inspecting magics (%foo?) works.
419 priority = 5
419 priority = 5
420
420
421 def __init__(self, start, q_locn):
421 def __init__(self, start, q_locn):
422 super().__init__(start)
422 super().__init__(start)
423 self.q_line = q_locn[0] - 1 # Shift from 1-indexed to 0-indexed
423 self.q_line = q_locn[0] - 1 # Shift from 1-indexed to 0-indexed
424 self.q_col = q_locn[1]
424 self.q_col = q_locn[1]
425
425
426 @classmethod
426 @classmethod
427 def find(cls, tokens_by_line):
427 def find(cls, tokens_by_line):
428 """Find the first help command (foo?) in the cell.
428 """Find the first help command (foo?) in the cell.
429 """
429 """
430 for line in tokens_by_line:
430 for line in tokens_by_line:
431 # Last token is NEWLINE; look at last but one
431 # Last token is NEWLINE; look at last but one
432 if len(line) > 2 and line[-2].string == '?':
432 if len(line) > 2 and line[-2].string == '?':
433 # Find the first token that's not INDENT/DEDENT
433 # Find the first token that's not INDENT/DEDENT
434 ix = 0
434 ix = 0
435 while line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
435 while line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
436 ix += 1
436 ix += 1
437 return cls(line[ix].start, line[-2].start)
437 return cls(line[ix].start, line[-2].start)
438
438
439 def transform(self, lines):
439 def transform(self, lines):
440 """Transform a help command found by the ``find()`` classmethod.
440 """Transform a help command found by the ``find()`` classmethod.
441 """
441 """
442 piece = ''.join(lines[self.start_line:self.q_line+1])
442 piece = ''.join(lines[self.start_line:self.q_line+1])
443 indent, content = piece[:self.start_col], piece[self.start_col:]
443 indent, content = piece[:self.start_col], piece[self.start_col:]
444 lines_before = lines[:self.start_line]
444 lines_before = lines[:self.start_line]
445 lines_after = lines[self.q_line + 1:]
445 lines_after = lines[self.q_line + 1:]
446
446
447 m = _help_end_re.search(content)
447 m = _help_end_re.search(content)
448 if not m:
448 if not m:
449 raise SyntaxError(content)
449 raise SyntaxError(content)
450 assert m is not None, content
450 assert m is not None, content
451 target = m.group(1)
451 target = m.group(1)
452 esc = m.group(3)
452 esc = m.group(3)
453
453
454 # If we're mid-command, put it back on the next prompt for the user.
454 # If we're mid-command, put it back on the next prompt for the user.
455 next_input = None
455 next_input = None
456 if (not lines_before) and (not lines_after) \
456 if (not lines_before) and (not lines_after) \
457 and content.strip() != m.group(0):
457 and content.strip() != m.group(0):
458 next_input = content.rstrip('?\n')
458 next_input = content.rstrip('?\n')
459
459
460 call = _make_help_call(target, esc, next_input=next_input)
460 call = _make_help_call(target, esc, next_input=next_input)
461 new_line = indent + call + '\n'
461 new_line = indent + call + '\n'
462
462
463 return lines_before + [new_line] + lines_after
463 return lines_before + [new_line] + lines_after
464
464
465 def make_tokens_by_line(lines:List[str]):
465 def make_tokens_by_line(lines:List[str]):
466 """Tokenize a series of lines and group tokens by line.
466 """Tokenize a series of lines and group tokens by line.
467
467
468 The tokens for a multiline Python string or expression are grouped as one
468 The tokens for a multiline Python string or expression are grouped as one
469 line. All lines except the last lines should keep their line ending ('\\n',
469 line. All lines except the last lines should keep their line ending ('\\n',
470 '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)`
470 '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)`
471 for example when passing block of text to this function.
471 for example when passing block of text to this function.
472
472
473 """
473 """
474 # NL tokens are used inside multiline expressions, but also after blank
474 # NL tokens are used inside multiline expressions, but also after blank
475 # lines or comments. This is intentional - see https://bugs.python.org/issue17061
475 # lines or comments. This is intentional - see https://bugs.python.org/issue17061
476 # We want to group the former case together but split the latter, so we
476 # We want to group the former case together but split the latter, so we
477 # track parentheses level, similar to the internals of tokenize.
477 # track parentheses level, similar to the internals of tokenize.
478 NEWLINE, NL = tokenize.NEWLINE, tokenize.NL
478 NEWLINE, NL = tokenize.NEWLINE, tokenize.NL
479 tokens_by_line = [[]]
479 tokens_by_line = [[]]
480 if len(lines) > 1 and not lines[0].endswith(('\n', '\r', '\r\n', '\x0b', '\x0c')):
480 if len(lines) > 1 and not lines[0].endswith(('\n', '\r', '\r\n', '\x0b', '\x0c')):
481 warnings.warn("`make_tokens_by_line` received a list of lines which do not have lineending markers ('\\n', '\\r', '\\r\\n', '\\x0b', '\\x0c'), behavior will be unspecified")
481 warnings.warn("`make_tokens_by_line` received a list of lines which do not have lineending markers ('\\n', '\\r', '\\r\\n', '\\x0b', '\\x0c'), behavior will be unspecified")
482 parenlev = 0
482 parenlev = 0
483 try:
483 try:
484 for token in tokenize.generate_tokens(iter(lines).__next__):
484 for token in tokenize.generate_tokens(iter(lines).__next__):
485 tokens_by_line[-1].append(token)
485 tokens_by_line[-1].append(token)
486 if (token.type == NEWLINE) \
486 if (token.type == NEWLINE) \
487 or ((token.type == NL) and (parenlev <= 0)):
487 or ((token.type == NL) and (parenlev <= 0)):
488 tokens_by_line.append([])
488 tokens_by_line.append([])
489 elif token.string in {'(', '[', '{'}:
489 elif token.string in {'(', '[', '{'}:
490 parenlev += 1
490 parenlev += 1
491 elif token.string in {')', ']', '}'}:
491 elif token.string in {')', ']', '}'}:
492 if parenlev > 0:
492 if parenlev > 0:
493 parenlev -= 1
493 parenlev -= 1
494 except tokenize.TokenError:
494 except tokenize.TokenError:
495 # Input ended in a multiline string or expression. That's OK for us.
495 # Input ended in a multiline string or expression. That's OK for us.
496 pass
496 pass
497
497
498
498
499 if not tokens_by_line[-1]:
499 if not tokens_by_line[-1]:
500 tokens_by_line.pop()
500 tokens_by_line.pop()
501
501
502
502
503 return tokens_by_line
503 return tokens_by_line
504
504
505 def show_linewise_tokens(s: str):
505 def show_linewise_tokens(s: str):
506 """For investigation and debugging"""
506 """For investigation and debugging"""
507 if not s.endswith('\n'):
507 if not s.endswith('\n'):
508 s += '\n'
508 s += '\n'
509 lines = s.splitlines(keepends=True)
509 lines = s.splitlines(keepends=True)
510 for line in make_tokens_by_line(lines):
510 for line in make_tokens_by_line(lines):
511 print("Line -------")
511 print("Line -------")
512 for tokinfo in line:
512 for tokinfo in line:
513 print(" ", tokinfo)
513 print(" ", tokinfo)
514
514
515 # Arbitrary limit to prevent getting stuck in infinite loops
515 # Arbitrary limit to prevent getting stuck in infinite loops
516 TRANSFORM_LOOP_LIMIT = 500
516 TRANSFORM_LOOP_LIMIT = 500
517
517
518 class TransformerManager:
518 class TransformerManager:
519 """Applies various transformations to a cell or code block.
519 """Applies various transformations to a cell or code block.
520
520
521 The key methods for external use are ``transform_cell()``
521 The key methods for external use are ``transform_cell()``
522 and ``check_complete()``.
522 and ``check_complete()``.
523 """
523 """
524 def __init__(self):
524 def __init__(self):
525 self.cleanup_transforms = [
525 self.cleanup_transforms = [
526 leading_empty_lines,
526 leading_empty_lines,
527 leading_indent,
527 leading_indent,
528 classic_prompt,
528 classic_prompt,
529 ipython_prompt,
529 ipython_prompt,
530 ]
530 ]
531 self.line_transforms = [
531 self.line_transforms = [
532 cell_magic,
532 cell_magic,
533 ]
533 ]
534 self.token_transformers = [
534 self.token_transformers = [
535 MagicAssign,
535 MagicAssign,
536 SystemAssign,
536 SystemAssign,
537 EscapedCommand,
537 EscapedCommand,
538 HelpEnd,
538 HelpEnd,
539 ]
539 ]
540
540
541 def do_one_token_transform(self, lines):
541 def do_one_token_transform(self, lines):
542 """Find and run the transform earliest in the code.
542 """Find and run the transform earliest in the code.
543
543
544 Returns (changed, lines).
544 Returns (changed, lines).
545
545
546 This method is called repeatedly until changed is False, indicating
546 This method is called repeatedly until changed is False, indicating
547 that all available transformations are complete.
547 that all available transformations are complete.
548
548
549 The tokens following IPython special syntax might not be valid, so
549 The tokens following IPython special syntax might not be valid, so
550 the transformed code is retokenised every time to identify the next
550 the transformed code is retokenised every time to identify the next
551 piece of special syntax. Hopefully long code cells are mostly valid
551 piece of special syntax. Hopefully long code cells are mostly valid
552 Python, not using lots of IPython special syntax, so this shouldn't be
552 Python, not using lots of IPython special syntax, so this shouldn't be
553 a performance issue.
553 a performance issue.
554 """
554 """
555 tokens_by_line = make_tokens_by_line(lines)
555 tokens_by_line = make_tokens_by_line(lines)
556 candidates = []
556 candidates = []
557 for transformer_cls in self.token_transformers:
557 for transformer_cls in self.token_transformers:
558 transformer = transformer_cls.find(tokens_by_line)
558 transformer = transformer_cls.find(tokens_by_line)
559 if transformer:
559 if transformer:
560 candidates.append(transformer)
560 candidates.append(transformer)
561
561
562 if not candidates:
562 if not candidates:
563 # Nothing to transform
563 # Nothing to transform
564 return False, lines
564 return False, lines
565 ordered_transformers = sorted(candidates, key=TokenTransformBase.sortby)
565 ordered_transformers = sorted(candidates, key=TokenTransformBase.sortby)
566 for transformer in ordered_transformers:
566 for transformer in ordered_transformers:
567 try:
567 try:
568 return True, transformer.transform(lines)
568 return True, transformer.transform(lines)
569 except SyntaxError:
569 except SyntaxError:
570 pass
570 pass
571 return False, lines
571 return False, lines
572
572
573 def do_token_transforms(self, lines):
573 def do_token_transforms(self, lines):
574 for _ in range(TRANSFORM_LOOP_LIMIT):
574 for _ in range(TRANSFORM_LOOP_LIMIT):
575 changed, lines = self.do_one_token_transform(lines)
575 changed, lines = self.do_one_token_transform(lines)
576 if not changed:
576 if not changed:
577 return lines
577 return lines
578
578
579 raise RuntimeError("Input transformation still changing after "
579 raise RuntimeError("Input transformation still changing after "
580 "%d iterations. Aborting." % TRANSFORM_LOOP_LIMIT)
580 "%d iterations. Aborting." % TRANSFORM_LOOP_LIMIT)
581
581
582 def transform_cell(self, cell: str) -> str:
582 def transform_cell(self, cell: str) -> str:
583 """Transforms a cell of input code"""
583 """Transforms a cell of input code"""
584 if not cell.endswith('\n'):
584 if not cell.endswith('\n'):
585 cell += '\n' # Ensure the cell has a trailing newline
585 cell += '\n' # Ensure the cell has a trailing newline
586 lines = cell.splitlines(keepends=True)
586 lines = cell.splitlines(keepends=True)
587 for transform in self.cleanup_transforms + self.line_transforms:
587 for transform in self.cleanup_transforms + self.line_transforms:
588 lines = transform(lines)
588 lines = transform(lines)
589
589
590 lines = self.do_token_transforms(lines)
590 lines = self.do_token_transforms(lines)
591 return ''.join(lines)
591 return ''.join(lines)
592
592
593 def check_complete(self, cell: str):
593 def check_complete(self, cell: str):
594 """Return whether a block of code is ready to execute, or should be continued
594 """Return whether a block of code is ready to execute, or should be continued
595
595
596 Parameters
596 Parameters
597 ----------
597 ----------
598 source : string
598 source : string
599 Python input code, which can be multiline.
599 Python input code, which can be multiline.
600
600
601 Returns
601 Returns
602 -------
602 -------
603 status : str
603 status : str
604 One of 'complete', 'incomplete', or 'invalid' if source is not a
604 One of 'complete', 'incomplete', or 'invalid' if source is not a
605 prefix of valid code.
605 prefix of valid code.
606 indent_spaces : int or None
606 indent_spaces : int or None
607 The number of spaces by which to indent the next line of code. If
607 The number of spaces by which to indent the next line of code. If
608 status is not 'incomplete', this is None.
608 status is not 'incomplete', this is None.
609 """
609 """
610 # Remember if the lines ends in a new line.
610 # Remember if the lines ends in a new line.
611 ends_with_newline = False
611 ends_with_newline = False
612 for character in reversed(cell):
612 for character in reversed(cell):
613 if character == '\n':
613 if character == '\n':
614 ends_with_newline = True
614 ends_with_newline = True
615 break
615 break
616 elif character.strip():
616 elif character.strip():
617 break
617 break
618 else:
618 else:
619 continue
619 continue
620
620
621 if not ends_with_newline:
621 if not ends_with_newline:
622 # Append an newline for consistent tokenization
622 # Append an newline for consistent tokenization
623 # See https://bugs.python.org/issue33899
623 # See https://bugs.python.org/issue33899
624 cell += '\n'
624 cell += '\n'
625
625
626 lines = cell.splitlines(keepends=True)
626 lines = cell.splitlines(keepends=True)
627
627
628 if not lines:
628 if not lines:
629 return 'complete', None
629 return 'complete', None
630
630
631 if lines[-1].endswith('\\'):
631 if lines[-1].endswith('\\'):
632 # Explicit backslash continuation
632 # Explicit backslash continuation
633 return 'incomplete', find_last_indent(lines)
633 return 'incomplete', find_last_indent(lines)
634
634
635 try:
635 try:
636 for transform in self.cleanup_transforms:
636 for transform in self.cleanup_transforms:
637 lines = transform(lines)
637 lines = transform(lines)
638 except SyntaxError:
638 except SyntaxError:
639 return 'invalid', None
639 return 'invalid', None
640
640
641 if lines[0].startswith('%%'):
641 if lines[0].startswith('%%'):
642 # Special case for cell magics - completion marked by blank line
642 # Special case for cell magics - completion marked by blank line
643 if lines[-1].strip():
643 if lines[-1].strip():
644 return 'incomplete', find_last_indent(lines)
644 return 'incomplete', find_last_indent(lines)
645 else:
645 else:
646 return 'complete', None
646 return 'complete', None
647
647
648 try:
648 try:
649 for transform in self.line_transforms:
649 for transform in self.line_transforms:
650 lines = transform(lines)
650 lines = transform(lines)
651 lines = self.do_token_transforms(lines)
651 lines = self.do_token_transforms(lines)
652 except SyntaxError:
652 except SyntaxError:
653 return 'invalid', None
653 return 'invalid', None
654
654
655 tokens_by_line = make_tokens_by_line(lines)
655 tokens_by_line = make_tokens_by_line(lines)
656
656
657 if not tokens_by_line:
657 if not tokens_by_line:
658 return 'incomplete', find_last_indent(lines)
658 return 'incomplete', find_last_indent(lines)
659
659
660 if tokens_by_line[-1][-1].type != tokenize.ENDMARKER:
660 if tokens_by_line[-1][-1].type != tokenize.ENDMARKER:
661 # We're in a multiline string or expression
661 # We're in a multiline string or expression
662 return 'incomplete', find_last_indent(lines)
662 return 'incomplete', find_last_indent(lines)
663
663
664 newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER}
664 newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER}
665
665
666 # Pop the last line which only contains DEDENTs and ENDMARKER
666 # Pop the last line which only contains DEDENTs and ENDMARKER
667 last_token_line = None
667 last_token_line = None
668 if {t.type for t in tokens_by_line[-1]} in [
668 if {t.type for t in tokens_by_line[-1]} in [
669 {tokenize.DEDENT, tokenize.ENDMARKER},
669 {tokenize.DEDENT, tokenize.ENDMARKER},
670 {tokenize.ENDMARKER}
670 {tokenize.ENDMARKER}
671 ] and len(tokens_by_line) > 1:
671 ] and len(tokens_by_line) > 1:
672 last_token_line = tokens_by_line.pop()
672 last_token_line = tokens_by_line.pop()
673
673
674 while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types:
674 while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types:
675 tokens_by_line[-1].pop()
675 tokens_by_line[-1].pop()
676
676
677 if not tokens_by_line[-1]:
677 if not tokens_by_line[-1]:
678 return 'incomplete', find_last_indent(lines)
678 return 'incomplete', find_last_indent(lines)
679
679
680 if tokens_by_line[-1][-1].string == ':':
680 if tokens_by_line[-1][-1].string == ':':
681 # The last line starts a block (e.g. 'if foo:')
681 # The last line starts a block (e.g. 'if foo:')
682 ix = 0
682 ix = 0
683 while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}:
683 while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}:
684 ix += 1
684 ix += 1
685
685
686 indent = tokens_by_line[-1][ix].start[1]
686 indent = tokens_by_line[-1][ix].start[1]
687 return 'incomplete', indent + 4
687 return 'incomplete', indent + 4
688
688
689 if tokens_by_line[-1][0].line.endswith('\\'):
689 if tokens_by_line[-1][0].line.endswith('\\'):
690 return 'incomplete', None
690 return 'incomplete', None
691
691
692 # At this point, our checks think the code is complete (or invalid).
692 # At this point, our checks think the code is complete (or invalid).
693 # We'll use codeop.compile_command to check this with the real parser
693 # We'll use codeop.compile_command to check this with the real parser
694 try:
694 try:
695 with warnings.catch_warnings():
695 with warnings.catch_warnings():
696 warnings.simplefilter('error', SyntaxWarning)
696 warnings.simplefilter('error', SyntaxWarning)
697 res = compile_command(''.join(lines), symbol='exec')
697 res = compile_command(''.join(lines), symbol='exec')
698 except (SyntaxError, OverflowError, ValueError, TypeError,
698 except (SyntaxError, OverflowError, ValueError, TypeError,
699 MemoryError, SyntaxWarning):
699 MemoryError, SyntaxWarning):
700 return 'invalid', None
700 return 'invalid', None
701 else:
701 else:
702 if res is None:
702 if res is None:
703 return 'incomplete', find_last_indent(lines)
703 return 'incomplete', find_last_indent(lines)
704
704
705 if last_token_line and last_token_line[0].type == tokenize.DEDENT:
705 if last_token_line and last_token_line[0].type == tokenize.DEDENT:
706 if ends_with_newline:
706 if ends_with_newline:
707 return 'complete', None
707 return 'complete', None
708 return 'incomplete', find_last_indent(lines)
708 return 'incomplete', find_last_indent(lines)
709
709
710 # If there's a blank line at the end, assume we're ready to execute
710 # If there's a blank line at the end, assume we're ready to execute
711 if not lines[-1].strip():
711 if not lines[-1].strip():
712 return 'complete', None
712 return 'complete', None
713
713
714 return 'complete', None
714 return 'complete', None
715
715
716
716
717 def find_last_indent(lines):
717 def find_last_indent(lines):
718 m = _indent_re.match(lines[-1])
718 m = _indent_re.match(lines[-1])
719 if not m:
719 if not m:
720 return 0
720 return 0
721 return len(m.group(0).replace('\t', ' '*4))
721 return len(m.group(0).replace('\t', ' '*4))
@@ -1,714 +1,708 b''
1 """Implementation of namespace-related magic functions.
1 """Implementation of namespace-related magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import gc
16 import gc
17 import re
17 import re
18 import sys
18 import sys
19
19
20 # Our own packages
20 # Our own packages
21 from IPython.core import page
21 from IPython.core import page
22 from IPython.core.error import StdinNotImplementedError, UsageError
22 from IPython.core.error import StdinNotImplementedError, UsageError
23 from IPython.core.magic import Magics, magics_class, line_magic
23 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.testing.skipdoctest import skip_doctest
24 from IPython.testing.skipdoctest import skip_doctest
25 from IPython.utils.encoding import DEFAULT_ENCODING
25 from IPython.utils.encoding import DEFAULT_ENCODING
26 from IPython.utils.openpy import read_py_file
26 from IPython.utils.openpy import read_py_file
27 from IPython.utils.path import get_py_filename
27 from IPython.utils.path import get_py_filename
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Magic implementation classes
30 # Magic implementation classes
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 @magics_class
33 @magics_class
34 class NamespaceMagics(Magics):
34 class NamespaceMagics(Magics):
35 """Magics to manage various aspects of the user's namespace.
35 """Magics to manage various aspects of the user's namespace.
36
36
37 These include listing variables, introspecting into them, etc.
37 These include listing variables, introspecting into them, etc.
38 """
38 """
39
39
40 @line_magic
40 @line_magic
41 def pinfo(self, parameter_s='', namespaces=None):
41 def pinfo(self, parameter_s='', namespaces=None):
42 """Provide detailed information about an object.
42 """Provide detailed information about an object.
43
43
44 '%pinfo object' is just a synonym for object? or ?object."""
44 '%pinfo object' is just a synonym for object? or ?object."""
45
45
46 #print 'pinfo par: <%s>' % parameter_s # dbg
46 #print 'pinfo par: <%s>' % parameter_s # dbg
47 # detail_level: 0 -> obj? , 1 -> obj??
47 # detail_level: 0 -> obj? , 1 -> obj??
48 detail_level = 0
48 detail_level = 0
49 # We need to detect if we got called as 'pinfo pinfo foo', which can
49 # We need to detect if we got called as 'pinfo pinfo foo', which can
50 # happen if the user types 'pinfo foo?' at the cmd line.
50 # happen if the user types 'pinfo foo?' at the cmd line.
51 pinfo,qmark1,oname,qmark2 = \
51 pinfo,qmark1,oname,qmark2 = \
52 re.match(r'(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
52 re.match(r'(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
53 if pinfo or qmark1 or qmark2:
53 if pinfo or qmark1 or qmark2:
54 detail_level = 1
54 detail_level = 1
55 if "*" in oname:
55 if "*" in oname:
56 self.psearch(oname)
56 self.psearch(oname)
57 else:
57 else:
58 self.shell._inspect('pinfo', oname, detail_level=detail_level,
58 self.shell._inspect('pinfo', oname, detail_level=detail_level,
59 namespaces=namespaces)
59 namespaces=namespaces)
60
60
61 @line_magic
61 @line_magic
62 def pinfo2(self, parameter_s='', namespaces=None):
62 def pinfo2(self, parameter_s='', namespaces=None):
63 """Provide extra detailed information about an object.
63 """Provide extra detailed information about an object.
64
64
65 '%pinfo2 object' is just a synonym for object?? or ??object."""
65 '%pinfo2 object' is just a synonym for object?? or ??object."""
66 self.shell._inspect('pinfo', parameter_s, detail_level=1,
66 self.shell._inspect('pinfo', parameter_s, detail_level=1,
67 namespaces=namespaces)
67 namespaces=namespaces)
68
68
69 @skip_doctest
69 @skip_doctest
70 @line_magic
70 @line_magic
71 def pdef(self, parameter_s='', namespaces=None):
71 def pdef(self, parameter_s='', namespaces=None):
72 """Print the call signature for any callable object.
72 """Print the call signature for any callable object.
73
73
74 If the object is a class, print the constructor information.
74 If the object is a class, print the constructor information.
75
75
76 Examples
76 Examples
77 --------
77 --------
78 ::
78 ::
79
79
80 In [3]: %pdef urllib.urlopen
80 In [3]: %pdef urllib.urlopen
81 urllib.urlopen(url, data=None, proxies=None)
81 urllib.urlopen(url, data=None, proxies=None)
82 """
82 """
83 self.shell._inspect('pdef',parameter_s, namespaces)
83 self.shell._inspect('pdef',parameter_s, namespaces)
84
84
85 @line_magic
85 @line_magic
86 def pdoc(self, parameter_s='', namespaces=None):
86 def pdoc(self, parameter_s='', namespaces=None):
87 """Print the docstring for an object.
87 """Print the docstring for an object.
88
88
89 If the given object is a class, it will print both the class and the
89 If the given object is a class, it will print both the class and the
90 constructor docstrings."""
90 constructor docstrings."""
91 self.shell._inspect('pdoc',parameter_s, namespaces)
91 self.shell._inspect('pdoc',parameter_s, namespaces)
92
92
93 @line_magic
93 @line_magic
94 def psource(self, parameter_s='', namespaces=None):
94 def psource(self, parameter_s='', namespaces=None):
95 """Print (or run through pager) the source code for an object."""
95 """Print (or run through pager) the source code for an object."""
96 if not parameter_s:
96 if not parameter_s:
97 raise UsageError('Missing object name.')
97 raise UsageError('Missing object name.')
98 self.shell._inspect('psource',parameter_s, namespaces)
98 self.shell._inspect('psource',parameter_s, namespaces)
99
99
100 @line_magic
100 @line_magic
101 def pfile(self, parameter_s='', namespaces=None):
101 def pfile(self, parameter_s='', namespaces=None):
102 """Print (or run through pager) the file where an object is defined.
102 """Print (or run through pager) the file where an object is defined.
103
103
104 The file opens at the line where the object definition begins. IPython
104 The file opens at the line where the object definition begins. IPython
105 will honor the environment variable PAGER if set, and otherwise will
105 will honor the environment variable PAGER if set, and otherwise will
106 do its best to print the file in a convenient form.
106 do its best to print the file in a convenient form.
107
107
108 If the given argument is not an object currently defined, IPython will
108 If the given argument is not an object currently defined, IPython will
109 try to interpret it as a filename (automatically adding a .py extension
109 try to interpret it as a filename (automatically adding a .py extension
110 if needed). You can thus use %pfile as a syntax highlighting code
110 if needed). You can thus use %pfile as a syntax highlighting code
111 viewer."""
111 viewer."""
112
112
113 # first interpret argument as an object name
113 # first interpret argument as an object name
114 out = self.shell._inspect('pfile',parameter_s, namespaces)
114 out = self.shell._inspect('pfile',parameter_s, namespaces)
115 # if not, try the input as a filename
115 # if not, try the input as a filename
116 if out == 'not found':
116 if out == 'not found':
117 try:
117 try:
118 filename = get_py_filename(parameter_s)
118 filename = get_py_filename(parameter_s)
119 except IOError as msg:
119 except IOError as msg:
120 print(msg)
120 print(msg)
121 return
121 return
122 page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
122 page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
123
123
124 @line_magic
124 @line_magic
125 def psearch(self, parameter_s=''):
125 def psearch(self, parameter_s=''):
126 """Search for object in namespaces by wildcard.
126 """Search for object in namespaces by wildcard.
127
127
128 %psearch [options] PATTERN [OBJECT TYPE]
128 %psearch [options] PATTERN [OBJECT TYPE]
129
129
130 Note: ? can be used as a synonym for %psearch, at the beginning or at
130 Note: ? can be used as a synonym for %psearch, at the beginning or at
131 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
131 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
132 rest of the command line must be unchanged (options come first), so
132 rest of the command line must be unchanged (options come first), so
133 for example the following forms are equivalent
133 for example the following forms are equivalent
134
134
135 %psearch -i a* function
135 %psearch -i a* function
136 -i a* function?
136 -i a* function?
137 ?-i a* function
137 ?-i a* function
138
138
139 Arguments:
139 Arguments:
140
140
141 PATTERN
141 PATTERN
142
142
143 where PATTERN is a string containing * as a wildcard similar to its
143 where PATTERN is a string containing * as a wildcard similar to its
144 use in a shell. The pattern is matched in all namespaces on the
144 use in a shell. The pattern is matched in all namespaces on the
145 search path. By default objects starting with a single _ are not
145 search path. By default objects starting with a single _ are not
146 matched, many IPython generated objects have a single
146 matched, many IPython generated objects have a single
147 underscore. The default is case insensitive matching. Matching is
147 underscore. The default is case insensitive matching. Matching is
148 also done on the attributes of objects and not only on the objects
148 also done on the attributes of objects and not only on the objects
149 in a module.
149 in a module.
150
150
151 [OBJECT TYPE]
151 [OBJECT TYPE]
152
152
153 Is the name of a python type from the types module. The name is
153 Is the name of a python type from the types module. The name is
154 given in lowercase without the ending type, ex. StringType is
154 given in lowercase without the ending type, ex. StringType is
155 written string. By adding a type here only objects matching the
155 written string. By adding a type here only objects matching the
156 given type are matched. Using all here makes the pattern match all
156 given type are matched. Using all here makes the pattern match all
157 types (this is the default).
157 types (this is the default).
158
158
159 Options:
159 Options:
160
160
161 -a: makes the pattern match even objects whose names start with a
161 -a: makes the pattern match even objects whose names start with a
162 single underscore. These names are normally omitted from the
162 single underscore. These names are normally omitted from the
163 search.
163 search.
164
164
165 -i/-c: make the pattern case insensitive/sensitive. If neither of
165 -i/-c: make the pattern case insensitive/sensitive. If neither of
166 these options are given, the default is read from your configuration
166 these options are given, the default is read from your configuration
167 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
167 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
168 If this option is not specified in your configuration file, IPython's
168 If this option is not specified in your configuration file, IPython's
169 internal default is to do a case sensitive search.
169 internal default is to do a case sensitive search.
170
170
171 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
171 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
172 specify can be searched in any of the following namespaces:
172 specify can be searched in any of the following namespaces:
173 'builtin', 'user', 'user_global','internal', 'alias', where
173 'builtin', 'user', 'user_global','internal', 'alias', where
174 'builtin' and 'user' are the search defaults. Note that you should
174 'builtin' and 'user' are the search defaults. Note that you should
175 not use quotes when specifying namespaces.
175 not use quotes when specifying namespaces.
176
176
177 -l: List all available object types for object matching. This function
177 -l: List all available object types for object matching. This function
178 can be used without arguments.
178 can be used without arguments.
179
179
180 'Builtin' contains the python module builtin, 'user' contains all
180 'Builtin' contains the python module builtin, 'user' contains all
181 user data, 'alias' only contain the shell aliases and no python
181 user data, 'alias' only contain the shell aliases and no python
182 objects, 'internal' contains objects used by IPython. The
182 objects, 'internal' contains objects used by IPython. The
183 'user_global' namespace is only used by embedded IPython instances,
183 'user_global' namespace is only used by embedded IPython instances,
184 and it contains module-level globals. You can add namespaces to the
184 and it contains module-level globals. You can add namespaces to the
185 search with -s or exclude them with -e (these options can be given
185 search with -s or exclude them with -e (these options can be given
186 more than once).
186 more than once).
187
187
188 Examples
188 Examples
189 --------
189 --------
190 ::
190 ::
191
191
192 %psearch a* -> objects beginning with an a
192 %psearch a* -> objects beginning with an a
193 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
193 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
194 %psearch a* function -> all functions beginning with an a
194 %psearch a* function -> all functions beginning with an a
195 %psearch re.e* -> objects beginning with an e in module re
195 %psearch re.e* -> objects beginning with an e in module re
196 %psearch r*.e* -> objects that start with e in modules starting in r
196 %psearch r*.e* -> objects that start with e in modules starting in r
197 %psearch r*.* string -> all strings in modules beginning with r
197 %psearch r*.* string -> all strings in modules beginning with r
198
198
199 Case sensitive search::
199 Case sensitive search::
200
200
201 %psearch -c a* list all object beginning with lower case a
201 %psearch -c a* list all object beginning with lower case a
202
202
203 Show objects beginning with a single _::
203 Show objects beginning with a single _::
204
204
205 %psearch -a _* list objects beginning with a single underscore
205 %psearch -a _* list objects beginning with a single underscore
206
206
207 List available objects::
207 List available objects::
208
208
209 %psearch -l list all available object types
209 %psearch -l list all available object types
210 """
210 """
211 try:
212 parameter_s.encode('ascii')
213 except UnicodeEncodeError:
214 print('Python identifiers can only contain ascii characters.')
215 return
216
217 # default namespaces to be searched
211 # default namespaces to be searched
218 def_search = ['user_local', 'user_global', 'builtin']
212 def_search = ['user_local', 'user_global', 'builtin']
219
213
220 # Process options/args
214 # Process options/args
221 opts,args = self.parse_options(parameter_s,'cias:e:l',list_all=True)
215 opts,args = self.parse_options(parameter_s,'cias:e:l',list_all=True)
222 opt = opts.get
216 opt = opts.get
223 shell = self.shell
217 shell = self.shell
224 psearch = shell.inspector.psearch
218 psearch = shell.inspector.psearch
225
219
226 # select list object types
220 # select list object types
227 list_types = False
221 list_types = False
228 if 'l' in opts:
222 if 'l' in opts:
229 list_types = True
223 list_types = True
230
224
231 # select case options
225 # select case options
232 if 'i' in opts:
226 if 'i' in opts:
233 ignore_case = True
227 ignore_case = True
234 elif 'c' in opts:
228 elif 'c' in opts:
235 ignore_case = False
229 ignore_case = False
236 else:
230 else:
237 ignore_case = not shell.wildcards_case_sensitive
231 ignore_case = not shell.wildcards_case_sensitive
238
232
239 # Build list of namespaces to search from user options
233 # Build list of namespaces to search from user options
240 def_search.extend(opt('s',[]))
234 def_search.extend(opt('s',[]))
241 ns_exclude = ns_exclude=opt('e',[])
235 ns_exclude = ns_exclude=opt('e',[])
242 ns_search = [nm for nm in def_search if nm not in ns_exclude]
236 ns_search = [nm for nm in def_search if nm not in ns_exclude]
243
237
244 # Call the actual search
238 # Call the actual search
245 try:
239 try:
246 psearch(args,shell.ns_table,ns_search,
240 psearch(args,shell.ns_table,ns_search,
247 show_all=opt('a'),ignore_case=ignore_case, list_types=list_types)
241 show_all=opt('a'),ignore_case=ignore_case, list_types=list_types)
248 except:
242 except:
249 shell.showtraceback()
243 shell.showtraceback()
250
244
251 @skip_doctest
245 @skip_doctest
252 @line_magic
246 @line_magic
253 def who_ls(self, parameter_s=''):
247 def who_ls(self, parameter_s=''):
254 """Return a sorted list of all interactive variables.
248 """Return a sorted list of all interactive variables.
255
249
256 If arguments are given, only variables of types matching these
250 If arguments are given, only variables of types matching these
257 arguments are returned.
251 arguments are returned.
258
252
259 Examples
253 Examples
260 --------
254 --------
261
255
262 Define two variables and list them with who_ls::
256 Define two variables and list them with who_ls::
263
257
264 In [1]: alpha = 123
258 In [1]: alpha = 123
265
259
266 In [2]: beta = 'test'
260 In [2]: beta = 'test'
267
261
268 In [3]: %who_ls
262 In [3]: %who_ls
269 Out[3]: ['alpha', 'beta']
263 Out[3]: ['alpha', 'beta']
270
264
271 In [4]: %who_ls int
265 In [4]: %who_ls int
272 Out[4]: ['alpha']
266 Out[4]: ['alpha']
273
267
274 In [5]: %who_ls str
268 In [5]: %who_ls str
275 Out[5]: ['beta']
269 Out[5]: ['beta']
276 """
270 """
277
271
278 user_ns = self.shell.user_ns
272 user_ns = self.shell.user_ns
279 user_ns_hidden = self.shell.user_ns_hidden
273 user_ns_hidden = self.shell.user_ns_hidden
280 nonmatching = object() # This can never be in user_ns
274 nonmatching = object() # This can never be in user_ns
281 out = [ i for i in user_ns
275 out = [ i for i in user_ns
282 if not i.startswith('_') \
276 if not i.startswith('_') \
283 and (user_ns[i] is not user_ns_hidden.get(i, nonmatching)) ]
277 and (user_ns[i] is not user_ns_hidden.get(i, nonmatching)) ]
284
278
285 typelist = parameter_s.split()
279 typelist = parameter_s.split()
286 if typelist:
280 if typelist:
287 typeset = set(typelist)
281 typeset = set(typelist)
288 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
282 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
289
283
290 out.sort()
284 out.sort()
291 return out
285 return out
292
286
293 @skip_doctest
287 @skip_doctest
294 @line_magic
288 @line_magic
295 def who(self, parameter_s=''):
289 def who(self, parameter_s=''):
296 """Print all interactive variables, with some minimal formatting.
290 """Print all interactive variables, with some minimal formatting.
297
291
298 If any arguments are given, only variables whose type matches one of
292 If any arguments are given, only variables whose type matches one of
299 these are printed. For example::
293 these are printed. For example::
300
294
301 %who function str
295 %who function str
302
296
303 will only list functions and strings, excluding all other types of
297 will only list functions and strings, excluding all other types of
304 variables. To find the proper type names, simply use type(var) at a
298 variables. To find the proper type names, simply use type(var) at a
305 command line to see how python prints type names. For example:
299 command line to see how python prints type names. For example:
306
300
307 ::
301 ::
308
302
309 In [1]: type('hello')\\
303 In [1]: type('hello')\\
310 Out[1]: <type 'str'>
304 Out[1]: <type 'str'>
311
305
312 indicates that the type name for strings is 'str'.
306 indicates that the type name for strings is 'str'.
313
307
314 ``%who`` always excludes executed names loaded through your configuration
308 ``%who`` always excludes executed names loaded through your configuration
315 file and things which are internal to IPython.
309 file and things which are internal to IPython.
316
310
317 This is deliberate, as typically you may load many modules and the
311 This is deliberate, as typically you may load many modules and the
318 purpose of %who is to show you only what you've manually defined.
312 purpose of %who is to show you only what you've manually defined.
319
313
320 Examples
314 Examples
321 --------
315 --------
322
316
323 Define two variables and list them with who::
317 Define two variables and list them with who::
324
318
325 In [1]: alpha = 123
319 In [1]: alpha = 123
326
320
327 In [2]: beta = 'test'
321 In [2]: beta = 'test'
328
322
329 In [3]: %who
323 In [3]: %who
330 alpha beta
324 alpha beta
331
325
332 In [4]: %who int
326 In [4]: %who int
333 alpha
327 alpha
334
328
335 In [5]: %who str
329 In [5]: %who str
336 beta
330 beta
337 """
331 """
338
332
339 varlist = self.who_ls(parameter_s)
333 varlist = self.who_ls(parameter_s)
340 if not varlist:
334 if not varlist:
341 if parameter_s:
335 if parameter_s:
342 print('No variables match your requested type.')
336 print('No variables match your requested type.')
343 else:
337 else:
344 print('Interactive namespace is empty.')
338 print('Interactive namespace is empty.')
345 return
339 return
346
340
347 # if we have variables, move on...
341 # if we have variables, move on...
348 count = 0
342 count = 0
349 for i in varlist:
343 for i in varlist:
350 print(i+'\t', end=' ')
344 print(i+'\t', end=' ')
351 count += 1
345 count += 1
352 if count > 8:
346 if count > 8:
353 count = 0
347 count = 0
354 print()
348 print()
355 print()
349 print()
356
350
357 @skip_doctest
351 @skip_doctest
358 @line_magic
352 @line_magic
359 def whos(self, parameter_s=''):
353 def whos(self, parameter_s=''):
360 """Like %who, but gives some extra information about each variable.
354 """Like %who, but gives some extra information about each variable.
361
355
362 The same type filtering of %who can be applied here.
356 The same type filtering of %who can be applied here.
363
357
364 For all variables, the type is printed. Additionally it prints:
358 For all variables, the type is printed. Additionally it prints:
365
359
366 - For {},[],(): their length.
360 - For {},[],(): their length.
367
361
368 - For numpy arrays, a summary with shape, number of
362 - For numpy arrays, a summary with shape, number of
369 elements, typecode and size in memory.
363 elements, typecode and size in memory.
370
364
371 - Everything else: a string representation, snipping their middle if
365 - Everything else: a string representation, snipping their middle if
372 too long.
366 too long.
373
367
374 Examples
368 Examples
375 --------
369 --------
376
370
377 Define two variables and list them with whos::
371 Define two variables and list them with whos::
378
372
379 In [1]: alpha = 123
373 In [1]: alpha = 123
380
374
381 In [2]: beta = 'test'
375 In [2]: beta = 'test'
382
376
383 In [3]: %whos
377 In [3]: %whos
384 Variable Type Data/Info
378 Variable Type Data/Info
385 --------------------------------
379 --------------------------------
386 alpha int 123
380 alpha int 123
387 beta str test
381 beta str test
388 """
382 """
389
383
390 varnames = self.who_ls(parameter_s)
384 varnames = self.who_ls(parameter_s)
391 if not varnames:
385 if not varnames:
392 if parameter_s:
386 if parameter_s:
393 print('No variables match your requested type.')
387 print('No variables match your requested type.')
394 else:
388 else:
395 print('Interactive namespace is empty.')
389 print('Interactive namespace is empty.')
396 return
390 return
397
391
398 # if we have variables, move on...
392 # if we have variables, move on...
399
393
400 # for these types, show len() instead of data:
394 # for these types, show len() instead of data:
401 seq_types = ['dict', 'list', 'tuple']
395 seq_types = ['dict', 'list', 'tuple']
402
396
403 # for numpy arrays, display summary info
397 # for numpy arrays, display summary info
404 ndarray_type = None
398 ndarray_type = None
405 if 'numpy' in sys.modules:
399 if 'numpy' in sys.modules:
406 try:
400 try:
407 from numpy import ndarray
401 from numpy import ndarray
408 except ImportError:
402 except ImportError:
409 pass
403 pass
410 else:
404 else:
411 ndarray_type = ndarray.__name__
405 ndarray_type = ndarray.__name__
412
406
413 # Find all variable names and types so we can figure out column sizes
407 # Find all variable names and types so we can figure out column sizes
414
408
415 # some types are well known and can be shorter
409 # some types are well known and can be shorter
416 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
410 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
417 def type_name(v):
411 def type_name(v):
418 tn = type(v).__name__
412 tn = type(v).__name__
419 return abbrevs.get(tn,tn)
413 return abbrevs.get(tn,tn)
420
414
421 varlist = [self.shell.user_ns[n] for n in varnames]
415 varlist = [self.shell.user_ns[n] for n in varnames]
422
416
423 typelist = []
417 typelist = []
424 for vv in varlist:
418 for vv in varlist:
425 tt = type_name(vv)
419 tt = type_name(vv)
426
420
427 if tt=='instance':
421 if tt=='instance':
428 typelist.append( abbrevs.get(str(vv.__class__),
422 typelist.append( abbrevs.get(str(vv.__class__),
429 str(vv.__class__)))
423 str(vv.__class__)))
430 else:
424 else:
431 typelist.append(tt)
425 typelist.append(tt)
432
426
433 # column labels and # of spaces as separator
427 # column labels and # of spaces as separator
434 varlabel = 'Variable'
428 varlabel = 'Variable'
435 typelabel = 'Type'
429 typelabel = 'Type'
436 datalabel = 'Data/Info'
430 datalabel = 'Data/Info'
437 colsep = 3
431 colsep = 3
438 # variable format strings
432 # variable format strings
439 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
433 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
440 aformat = "%s: %s elems, type `%s`, %s bytes"
434 aformat = "%s: %s elems, type `%s`, %s bytes"
441 # find the size of the columns to format the output nicely
435 # find the size of the columns to format the output nicely
442 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
436 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
443 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
437 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
444 # table header
438 # table header
445 print(varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
439 print(varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
446 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1))
440 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1))
447 # and the table itself
441 # and the table itself
448 kb = 1024
442 kb = 1024
449 Mb = 1048576 # kb**2
443 Mb = 1048576 # kb**2
450 for vname,var,vtype in zip(varnames,varlist,typelist):
444 for vname,var,vtype in zip(varnames,varlist,typelist):
451 print(vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), end=' ')
445 print(vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), end=' ')
452 if vtype in seq_types:
446 if vtype in seq_types:
453 print("n="+str(len(var)))
447 print("n="+str(len(var)))
454 elif vtype == ndarray_type:
448 elif vtype == ndarray_type:
455 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
449 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
456 if vtype==ndarray_type:
450 if vtype==ndarray_type:
457 # numpy
451 # numpy
458 vsize = var.size
452 vsize = var.size
459 vbytes = vsize*var.itemsize
453 vbytes = vsize*var.itemsize
460 vdtype = var.dtype
454 vdtype = var.dtype
461
455
462 if vbytes < 100000:
456 if vbytes < 100000:
463 print(aformat % (vshape, vsize, vdtype, vbytes))
457 print(aformat % (vshape, vsize, vdtype, vbytes))
464 else:
458 else:
465 print(aformat % (vshape, vsize, vdtype, vbytes), end=' ')
459 print(aformat % (vshape, vsize, vdtype, vbytes), end=' ')
466 if vbytes < Mb:
460 if vbytes < Mb:
467 print('(%s kb)' % (vbytes/kb,))
461 print('(%s kb)' % (vbytes/kb,))
468 else:
462 else:
469 print('(%s Mb)' % (vbytes/Mb,))
463 print('(%s Mb)' % (vbytes/Mb,))
470 else:
464 else:
471 try:
465 try:
472 vstr = str(var)
466 vstr = str(var)
473 except UnicodeEncodeError:
467 except UnicodeEncodeError:
474 vstr = var.encode(DEFAULT_ENCODING,
468 vstr = var.encode(DEFAULT_ENCODING,
475 'backslashreplace')
469 'backslashreplace')
476 except:
470 except:
477 vstr = "<object with id %d (str() failed)>" % id(var)
471 vstr = "<object with id %d (str() failed)>" % id(var)
478 vstr = vstr.replace('\n', '\\n')
472 vstr = vstr.replace('\n', '\\n')
479 if len(vstr) < 50:
473 if len(vstr) < 50:
480 print(vstr)
474 print(vstr)
481 else:
475 else:
482 print(vstr[:25] + "<...>" + vstr[-25:])
476 print(vstr[:25] + "<...>" + vstr[-25:])
483
477
484 @line_magic
478 @line_magic
485 def reset(self, parameter_s=''):
479 def reset(self, parameter_s=''):
486 """Resets the namespace by removing all names defined by the user, if
480 """Resets the namespace by removing all names defined by the user, if
487 called without arguments, or by removing some types of objects, such
481 called without arguments, or by removing some types of objects, such
488 as everything currently in IPython's In[] and Out[] containers (see
482 as everything currently in IPython's In[] and Out[] containers (see
489 the parameters for details).
483 the parameters for details).
490
484
491 Parameters
485 Parameters
492 ----------
486 ----------
493 -f : force reset without asking for confirmation.
487 -f : force reset without asking for confirmation.
494
488
495 -s : 'Soft' reset: Only clears your namespace, leaving history intact.
489 -s : 'Soft' reset: Only clears your namespace, leaving history intact.
496 References to objects may be kept. By default (without this option),
490 References to objects may be kept. By default (without this option),
497 we do a 'hard' reset, giving you a new session and removing all
491 we do a 'hard' reset, giving you a new session and removing all
498 references to objects from the current session.
492 references to objects from the current session.
499
493
500 in : reset input history
494 in : reset input history
501
495
502 out : reset output history
496 out : reset output history
503
497
504 dhist : reset directory history
498 dhist : reset directory history
505
499
506 array : reset only variables that are NumPy arrays
500 array : reset only variables that are NumPy arrays
507
501
508 See Also
502 See Also
509 --------
503 --------
510 reset_selective : invoked as ``%reset_selective``
504 reset_selective : invoked as ``%reset_selective``
511
505
512 Examples
506 Examples
513 --------
507 --------
514 ::
508 ::
515
509
516 In [6]: a = 1
510 In [6]: a = 1
517
511
518 In [7]: a
512 In [7]: a
519 Out[7]: 1
513 Out[7]: 1
520
514
521 In [8]: 'a' in get_ipython().user_ns
515 In [8]: 'a' in get_ipython().user_ns
522 Out[8]: True
516 Out[8]: True
523
517
524 In [9]: %reset -f
518 In [9]: %reset -f
525
519
526 In [1]: 'a' in get_ipython().user_ns
520 In [1]: 'a' in get_ipython().user_ns
527 Out[1]: False
521 Out[1]: False
528
522
529 In [2]: %reset -f in
523 In [2]: %reset -f in
530 Flushing input history
524 Flushing input history
531
525
532 In [3]: %reset -f dhist in
526 In [3]: %reset -f dhist in
533 Flushing directory history
527 Flushing directory history
534 Flushing input history
528 Flushing input history
535
529
536 Notes
530 Notes
537 -----
531 -----
538 Calling this magic from clients that do not implement standard input,
532 Calling this magic from clients that do not implement standard input,
539 such as the ipython notebook interface, will reset the namespace
533 such as the ipython notebook interface, will reset the namespace
540 without confirmation.
534 without confirmation.
541 """
535 """
542 opts, args = self.parse_options(parameter_s,'sf', mode='list')
536 opts, args = self.parse_options(parameter_s,'sf', mode='list')
543 if 'f' in opts:
537 if 'f' in opts:
544 ans = True
538 ans = True
545 else:
539 else:
546 try:
540 try:
547 ans = self.shell.ask_yes_no(
541 ans = self.shell.ask_yes_no(
548 "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
542 "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
549 default='n')
543 default='n')
550 except StdinNotImplementedError:
544 except StdinNotImplementedError:
551 ans = True
545 ans = True
552 if not ans:
546 if not ans:
553 print('Nothing done.')
547 print('Nothing done.')
554 return
548 return
555
549
556 if 's' in opts: # Soft reset
550 if 's' in opts: # Soft reset
557 user_ns = self.shell.user_ns
551 user_ns = self.shell.user_ns
558 for i in self.who_ls():
552 for i in self.who_ls():
559 del(user_ns[i])
553 del(user_ns[i])
560 elif len(args) == 0: # Hard reset
554 elif len(args) == 0: # Hard reset
561 self.shell.reset(new_session = False)
555 self.shell.reset(new_session = False)
562
556
563 # reset in/out/dhist/array: previously extensinions/clearcmd.py
557 # reset in/out/dhist/array: previously extensinions/clearcmd.py
564 ip = self.shell
558 ip = self.shell
565 user_ns = self.shell.user_ns # local lookup, heavily used
559 user_ns = self.shell.user_ns # local lookup, heavily used
566
560
567 for target in args:
561 for target in args:
568 target = target.lower() # make matches case insensitive
562 target = target.lower() # make matches case insensitive
569 if target == 'out':
563 if target == 'out':
570 print("Flushing output cache (%d entries)" % len(user_ns['_oh']))
564 print("Flushing output cache (%d entries)" % len(user_ns['_oh']))
571 self.shell.displayhook.flush()
565 self.shell.displayhook.flush()
572
566
573 elif target == 'in':
567 elif target == 'in':
574 print("Flushing input history")
568 print("Flushing input history")
575 pc = self.shell.displayhook.prompt_count + 1
569 pc = self.shell.displayhook.prompt_count + 1
576 for n in range(1, pc):
570 for n in range(1, pc):
577 key = '_i'+repr(n)
571 key = '_i'+repr(n)
578 user_ns.pop(key,None)
572 user_ns.pop(key,None)
579 user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
573 user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
580 hm = ip.history_manager
574 hm = ip.history_manager
581 # don't delete these, as %save and %macro depending on the
575 # don't delete these, as %save and %macro depending on the
582 # length of these lists to be preserved
576 # length of these lists to be preserved
583 hm.input_hist_parsed[:] = [''] * pc
577 hm.input_hist_parsed[:] = [''] * pc
584 hm.input_hist_raw[:] = [''] * pc
578 hm.input_hist_raw[:] = [''] * pc
585 # hm has internal machinery for _i,_ii,_iii, clear it out
579 # hm has internal machinery for _i,_ii,_iii, clear it out
586 hm._i = hm._ii = hm._iii = hm._i00 = u''
580 hm._i = hm._ii = hm._iii = hm._i00 = u''
587
581
588 elif target == 'array':
582 elif target == 'array':
589 # Support cleaning up numpy arrays
583 # Support cleaning up numpy arrays
590 try:
584 try:
591 from numpy import ndarray
585 from numpy import ndarray
592 # This must be done with items and not iteritems because
586 # This must be done with items and not iteritems because
593 # we're going to modify the dict in-place.
587 # we're going to modify the dict in-place.
594 for x,val in list(user_ns.items()):
588 for x,val in list(user_ns.items()):
595 if isinstance(val,ndarray):
589 if isinstance(val,ndarray):
596 del user_ns[x]
590 del user_ns[x]
597 except ImportError:
591 except ImportError:
598 print("reset array only works if Numpy is available.")
592 print("reset array only works if Numpy is available.")
599
593
600 elif target == 'dhist':
594 elif target == 'dhist':
601 print("Flushing directory history")
595 print("Flushing directory history")
602 del user_ns['_dh'][:]
596 del user_ns['_dh'][:]
603
597
604 else:
598 else:
605 print("Don't know how to reset ", end=' ')
599 print("Don't know how to reset ", end=' ')
606 print(target + ", please run `%reset?` for details")
600 print(target + ", please run `%reset?` for details")
607
601
608 gc.collect()
602 gc.collect()
609
603
610 @line_magic
604 @line_magic
611 def reset_selective(self, parameter_s=''):
605 def reset_selective(self, parameter_s=''):
612 """Resets the namespace by removing names defined by the user.
606 """Resets the namespace by removing names defined by the user.
613
607
614 Input/Output history are left around in case you need them.
608 Input/Output history are left around in case you need them.
615
609
616 %reset_selective [-f] regex
610 %reset_selective [-f] regex
617
611
618 No action is taken if regex is not included
612 No action is taken if regex is not included
619
613
620 Options
614 Options
621 -f : force reset without asking for confirmation.
615 -f : force reset without asking for confirmation.
622
616
623 See Also
617 See Also
624 --------
618 --------
625 reset : invoked as ``%reset``
619 reset : invoked as ``%reset``
626
620
627 Examples
621 Examples
628 --------
622 --------
629
623
630 We first fully reset the namespace so your output looks identical to
624 We first fully reset the namespace so your output looks identical to
631 this example for pedagogical reasons; in practice you do not need a
625 this example for pedagogical reasons; in practice you do not need a
632 full reset::
626 full reset::
633
627
634 In [1]: %reset -f
628 In [1]: %reset -f
635
629
636 Now, with a clean namespace we can make a few variables and use
630 Now, with a clean namespace we can make a few variables and use
637 ``%reset_selective`` to only delete names that match our regexp::
631 ``%reset_selective`` to only delete names that match our regexp::
638
632
639 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
633 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
640
634
641 In [3]: who_ls
635 In [3]: who_ls
642 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
636 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
643
637
644 In [4]: %reset_selective -f b[2-3]m
638 In [4]: %reset_selective -f b[2-3]m
645
639
646 In [5]: who_ls
640 In [5]: who_ls
647 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
641 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
648
642
649 In [6]: %reset_selective -f d
643 In [6]: %reset_selective -f d
650
644
651 In [7]: who_ls
645 In [7]: who_ls
652 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
646 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
653
647
654 In [8]: %reset_selective -f c
648 In [8]: %reset_selective -f c
655
649
656 In [9]: who_ls
650 In [9]: who_ls
657 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
651 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
658
652
659 In [10]: %reset_selective -f b
653 In [10]: %reset_selective -f b
660
654
661 In [11]: who_ls
655 In [11]: who_ls
662 Out[11]: ['a']
656 Out[11]: ['a']
663
657
664 Notes
658 Notes
665 -----
659 -----
666 Calling this magic from clients that do not implement standard input,
660 Calling this magic from clients that do not implement standard input,
667 such as the ipython notebook interface, will reset the namespace
661 such as the ipython notebook interface, will reset the namespace
668 without confirmation.
662 without confirmation.
669 """
663 """
670
664
671 opts, regex = self.parse_options(parameter_s,'f')
665 opts, regex = self.parse_options(parameter_s,'f')
672
666
673 if 'f' in opts:
667 if 'f' in opts:
674 ans = True
668 ans = True
675 else:
669 else:
676 try:
670 try:
677 ans = self.shell.ask_yes_no(
671 ans = self.shell.ask_yes_no(
678 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
672 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
679 default='n')
673 default='n')
680 except StdinNotImplementedError:
674 except StdinNotImplementedError:
681 ans = True
675 ans = True
682 if not ans:
676 if not ans:
683 print('Nothing done.')
677 print('Nothing done.')
684 return
678 return
685 user_ns = self.shell.user_ns
679 user_ns = self.shell.user_ns
686 if not regex:
680 if not regex:
687 print('No regex pattern specified. Nothing done.')
681 print('No regex pattern specified. Nothing done.')
688 return
682 return
689 else:
683 else:
690 try:
684 try:
691 m = re.compile(regex)
685 m = re.compile(regex)
692 except TypeError:
686 except TypeError:
693 raise TypeError('regex must be a string or compiled pattern')
687 raise TypeError('regex must be a string or compiled pattern')
694 for i in self.who_ls():
688 for i in self.who_ls():
695 if m.search(i):
689 if m.search(i):
696 del(user_ns[i])
690 del(user_ns[i])
697
691
698 @line_magic
692 @line_magic
699 def xdel(self, parameter_s=''):
693 def xdel(self, parameter_s=''):
700 """Delete a variable, trying to clear it from anywhere that
694 """Delete a variable, trying to clear it from anywhere that
701 IPython's machinery has references to it. By default, this uses
695 IPython's machinery has references to it. By default, this uses
702 the identity of the named object in the user namespace to remove
696 the identity of the named object in the user namespace to remove
703 references held under other names. The object is also removed
697 references held under other names. The object is also removed
704 from the output history.
698 from the output history.
705
699
706 Options
700 Options
707 -n : Delete the specified name from all namespaces, without
701 -n : Delete the specified name from all namespaces, without
708 checking their identity.
702 checking their identity.
709 """
703 """
710 opts, varname = self.parse_options(parameter_s,'n')
704 opts, varname = self.parse_options(parameter_s,'n')
711 try:
705 try:
712 self.shell.del_var(varname, ('n' in opts))
706 self.shell.del_var(varname, ('n' in opts))
713 except (NameError, ValueError) as e:
707 except (NameError, ValueError) as e:
714 print(type(e).__name__ +": "+ str(e))
708 print(type(e).__name__ +": "+ str(e))
@@ -1,709 +1,709 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Prefiltering components.
3 Prefiltering components.
4
4
5 Prefilters transform user input before it is exec'd by Python. These
5 Prefilters transform user input before it is exec'd by Python. These
6 transforms are used to implement additional syntax such as !ls and %magic.
6 transforms are used to implement additional syntax such as !ls and %magic.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 from keyword import iskeyword
12 from keyword import iskeyword
13 import re
13 import re
14
14
15 from .autocall import IPyAutocall
15 from .autocall import IPyAutocall
16 from traitlets.config.configurable import Configurable
16 from traitlets.config.configurable import Configurable
17 from .inputtransformer2 import (
17 from .inputtransformer2 import (
18 ESC_MAGIC,
18 ESC_MAGIC,
19 ESC_QUOTE,
19 ESC_QUOTE,
20 ESC_QUOTE2,
20 ESC_QUOTE2,
21 ESC_PAREN,
21 ESC_PAREN,
22 )
22 )
23 from .macro import Macro
23 from .macro import Macro
24 from .splitinput import LineInfo
24 from .splitinput import LineInfo
25
25
26 from traitlets import (
26 from traitlets import (
27 List, Integer, Unicode, Bool, Instance, CRegExp
27 List, Integer, Unicode, Bool, Instance, CRegExp
28 )
28 )
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Global utilities, errors and constants
31 # Global utilities, errors and constants
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34
34
35 class PrefilterError(Exception):
35 class PrefilterError(Exception):
36 pass
36 pass
37
37
38
38
39 # RegExp to identify potential function names
39 # RegExp to identify potential function names
40 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
40 re_fun_name = re.compile(r'[^\W\d]([\w.]*) *$')
41
41
42 # RegExp to exclude strings with this start from autocalling. In
42 # RegExp to exclude strings with this start from autocalling. In
43 # particular, all binary operators should be excluded, so that if foo is
43 # particular, all binary operators should be excluded, so that if foo is
44 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
44 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
45 # characters '!=()' don't need to be checked for, as the checkPythonChars
45 # characters '!=()' don't need to be checked for, as the checkPythonChars
46 # routine explicitly does so, to catch direct calls and rebindings of
46 # routine explicitly does so, to catch direct calls and rebindings of
47 # existing names.
47 # existing names.
48
48
49 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
49 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
50 # it affects the rest of the group in square brackets.
50 # it affects the rest of the group in square brackets.
51 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
51 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
52 r'|^is |^not |^in |^and |^or ')
52 r'|^is |^not |^in |^and |^or ')
53
53
54 # try to catch also methods for stuff in lists/tuples/dicts: off
54 # try to catch also methods for stuff in lists/tuples/dicts: off
55 # (experimental). For this to work, the line_split regexp would need
55 # (experimental). For this to work, the line_split regexp would need
56 # to be modified so it wouldn't break things at '['. That line is
56 # to be modified so it wouldn't break things at '['. That line is
57 # nasty enough that I shouldn't change it until I can test it _well_.
57 # nasty enough that I shouldn't change it until I can test it _well_.
58 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
58 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
59
59
60
60
61 # Handler Check Utilities
61 # Handler Check Utilities
62 def is_shadowed(identifier, ip):
62 def is_shadowed(identifier, ip):
63 """Is the given identifier defined in one of the namespaces which shadow
63 """Is the given identifier defined in one of the namespaces which shadow
64 the alias and magic namespaces? Note that an identifier is different
64 the alias and magic namespaces? Note that an identifier is different
65 than ifun, because it can not contain a '.' character."""
65 than ifun, because it can not contain a '.' character."""
66 # This is much safer than calling ofind, which can change state
66 # This is much safer than calling ofind, which can change state
67 return (identifier in ip.user_ns \
67 return (identifier in ip.user_ns \
68 or identifier in ip.user_global_ns \
68 or identifier in ip.user_global_ns \
69 or identifier in ip.ns_table['builtin']\
69 or identifier in ip.ns_table['builtin']\
70 or iskeyword(identifier))
70 or iskeyword(identifier))
71
71
72
72
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74 # Main Prefilter manager
74 # Main Prefilter manager
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76
76
77
77
78 class PrefilterManager(Configurable):
78 class PrefilterManager(Configurable):
79 """Main prefilter component.
79 """Main prefilter component.
80
80
81 The IPython prefilter is run on all user input before it is run. The
81 The IPython prefilter is run on all user input before it is run. The
82 prefilter consumes lines of input and produces transformed lines of
82 prefilter consumes lines of input and produces transformed lines of
83 input.
83 input.
84
84
85 The implementation consists of two phases:
85 The implementation consists of two phases:
86
86
87 1. Transformers
87 1. Transformers
88 2. Checkers and handlers
88 2. Checkers and handlers
89
89
90 Over time, we plan on deprecating the checkers and handlers and doing
90 Over time, we plan on deprecating the checkers and handlers and doing
91 everything in the transformers.
91 everything in the transformers.
92
92
93 The transformers are instances of :class:`PrefilterTransformer` and have
93 The transformers are instances of :class:`PrefilterTransformer` and have
94 a single method :meth:`transform` that takes a line and returns a
94 a single method :meth:`transform` that takes a line and returns a
95 transformed line. The transformation can be accomplished using any
95 transformed line. The transformation can be accomplished using any
96 tool, but our current ones use regular expressions for speed.
96 tool, but our current ones use regular expressions for speed.
97
97
98 After all the transformers have been run, the line is fed to the checkers,
98 After all the transformers have been run, the line is fed to the checkers,
99 which are instances of :class:`PrefilterChecker`. The line is passed to
99 which are instances of :class:`PrefilterChecker`. The line is passed to
100 the :meth:`check` method, which either returns `None` or a
100 the :meth:`check` method, which either returns `None` or a
101 :class:`PrefilterHandler` instance. If `None` is returned, the other
101 :class:`PrefilterHandler` instance. If `None` is returned, the other
102 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
102 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
103 the line is passed to the :meth:`handle` method of the returned
103 the line is passed to the :meth:`handle` method of the returned
104 handler and no further checkers are tried.
104 handler and no further checkers are tried.
105
105
106 Both transformers and checkers have a `priority` attribute, that determines
106 Both transformers and checkers have a `priority` attribute, that determines
107 the order in which they are called. Smaller priorities are tried first.
107 the order in which they are called. Smaller priorities are tried first.
108
108
109 Both transformers and checkers also have `enabled` attribute, which is
109 Both transformers and checkers also have `enabled` attribute, which is
110 a boolean that determines if the instance is used.
110 a boolean that determines if the instance is used.
111
111
112 Users or developers can change the priority or enabled attribute of
112 Users or developers can change the priority or enabled attribute of
113 transformers or checkers, but they must call the :meth:`sort_checkers`
113 transformers or checkers, but they must call the :meth:`sort_checkers`
114 or :meth:`sort_transformers` method after changing the priority.
114 or :meth:`sort_transformers` method after changing the priority.
115 """
115 """
116
116
117 multi_line_specials = Bool(True).tag(config=True)
117 multi_line_specials = Bool(True).tag(config=True)
118 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
118 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
119
119
120 def __init__(self, shell=None, **kwargs):
120 def __init__(self, shell=None, **kwargs):
121 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
121 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
122 self.shell = shell
122 self.shell = shell
123 self.init_transformers()
123 self.init_transformers()
124 self.init_handlers()
124 self.init_handlers()
125 self.init_checkers()
125 self.init_checkers()
126
126
127 #-------------------------------------------------------------------------
127 #-------------------------------------------------------------------------
128 # API for managing transformers
128 # API for managing transformers
129 #-------------------------------------------------------------------------
129 #-------------------------------------------------------------------------
130
130
131 def init_transformers(self):
131 def init_transformers(self):
132 """Create the default transformers."""
132 """Create the default transformers."""
133 self._transformers = []
133 self._transformers = []
134 for transformer_cls in _default_transformers:
134 for transformer_cls in _default_transformers:
135 transformer_cls(
135 transformer_cls(
136 shell=self.shell, prefilter_manager=self, parent=self
136 shell=self.shell, prefilter_manager=self, parent=self
137 )
137 )
138
138
139 def sort_transformers(self):
139 def sort_transformers(self):
140 """Sort the transformers by priority.
140 """Sort the transformers by priority.
141
141
142 This must be called after the priority of a transformer is changed.
142 This must be called after the priority of a transformer is changed.
143 The :meth:`register_transformer` method calls this automatically.
143 The :meth:`register_transformer` method calls this automatically.
144 """
144 """
145 self._transformers.sort(key=lambda x: x.priority)
145 self._transformers.sort(key=lambda x: x.priority)
146
146
147 @property
147 @property
148 def transformers(self):
148 def transformers(self):
149 """Return a list of checkers, sorted by priority."""
149 """Return a list of checkers, sorted by priority."""
150 return self._transformers
150 return self._transformers
151
151
152 def register_transformer(self, transformer):
152 def register_transformer(self, transformer):
153 """Register a transformer instance."""
153 """Register a transformer instance."""
154 if transformer not in self._transformers:
154 if transformer not in self._transformers:
155 self._transformers.append(transformer)
155 self._transformers.append(transformer)
156 self.sort_transformers()
156 self.sort_transformers()
157
157
158 def unregister_transformer(self, transformer):
158 def unregister_transformer(self, transformer):
159 """Unregister a transformer instance."""
159 """Unregister a transformer instance."""
160 if transformer in self._transformers:
160 if transformer in self._transformers:
161 self._transformers.remove(transformer)
161 self._transformers.remove(transformer)
162
162
163 #-------------------------------------------------------------------------
163 #-------------------------------------------------------------------------
164 # API for managing checkers
164 # API for managing checkers
165 #-------------------------------------------------------------------------
165 #-------------------------------------------------------------------------
166
166
167 def init_checkers(self):
167 def init_checkers(self):
168 """Create the default checkers."""
168 """Create the default checkers."""
169 self._checkers = []
169 self._checkers = []
170 for checker in _default_checkers:
170 for checker in _default_checkers:
171 checker(
171 checker(
172 shell=self.shell, prefilter_manager=self, parent=self
172 shell=self.shell, prefilter_manager=self, parent=self
173 )
173 )
174
174
175 def sort_checkers(self):
175 def sort_checkers(self):
176 """Sort the checkers by priority.
176 """Sort the checkers by priority.
177
177
178 This must be called after the priority of a checker is changed.
178 This must be called after the priority of a checker is changed.
179 The :meth:`register_checker` method calls this automatically.
179 The :meth:`register_checker` method calls this automatically.
180 """
180 """
181 self._checkers.sort(key=lambda x: x.priority)
181 self._checkers.sort(key=lambda x: x.priority)
182
182
183 @property
183 @property
184 def checkers(self):
184 def checkers(self):
185 """Return a list of checkers, sorted by priority."""
185 """Return a list of checkers, sorted by priority."""
186 return self._checkers
186 return self._checkers
187
187
188 def register_checker(self, checker):
188 def register_checker(self, checker):
189 """Register a checker instance."""
189 """Register a checker instance."""
190 if checker not in self._checkers:
190 if checker not in self._checkers:
191 self._checkers.append(checker)
191 self._checkers.append(checker)
192 self.sort_checkers()
192 self.sort_checkers()
193
193
194 def unregister_checker(self, checker):
194 def unregister_checker(self, checker):
195 """Unregister a checker instance."""
195 """Unregister a checker instance."""
196 if checker in self._checkers:
196 if checker in self._checkers:
197 self._checkers.remove(checker)
197 self._checkers.remove(checker)
198
198
199 #-------------------------------------------------------------------------
199 #-------------------------------------------------------------------------
200 # API for managing handlers
200 # API for managing handlers
201 #-------------------------------------------------------------------------
201 #-------------------------------------------------------------------------
202
202
203 def init_handlers(self):
203 def init_handlers(self):
204 """Create the default handlers."""
204 """Create the default handlers."""
205 self._handlers = {}
205 self._handlers = {}
206 self._esc_handlers = {}
206 self._esc_handlers = {}
207 for handler in _default_handlers:
207 for handler in _default_handlers:
208 handler(
208 handler(
209 shell=self.shell, prefilter_manager=self, parent=self
209 shell=self.shell, prefilter_manager=self, parent=self
210 )
210 )
211
211
212 @property
212 @property
213 def handlers(self):
213 def handlers(self):
214 """Return a dict of all the handlers."""
214 """Return a dict of all the handlers."""
215 return self._handlers
215 return self._handlers
216
216
217 def register_handler(self, name, handler, esc_strings):
217 def register_handler(self, name, handler, esc_strings):
218 """Register a handler instance by name with esc_strings."""
218 """Register a handler instance by name with esc_strings."""
219 self._handlers[name] = handler
219 self._handlers[name] = handler
220 for esc_str in esc_strings:
220 for esc_str in esc_strings:
221 self._esc_handlers[esc_str] = handler
221 self._esc_handlers[esc_str] = handler
222
222
223 def unregister_handler(self, name, handler, esc_strings):
223 def unregister_handler(self, name, handler, esc_strings):
224 """Unregister a handler instance by name with esc_strings."""
224 """Unregister a handler instance by name with esc_strings."""
225 try:
225 try:
226 del self._handlers[name]
226 del self._handlers[name]
227 except KeyError:
227 except KeyError:
228 pass
228 pass
229 for esc_str in esc_strings:
229 for esc_str in esc_strings:
230 h = self._esc_handlers.get(esc_str)
230 h = self._esc_handlers.get(esc_str)
231 if h is handler:
231 if h is handler:
232 del self._esc_handlers[esc_str]
232 del self._esc_handlers[esc_str]
233
233
234 def get_handler_by_name(self, name):
234 def get_handler_by_name(self, name):
235 """Get a handler by its name."""
235 """Get a handler by its name."""
236 return self._handlers.get(name)
236 return self._handlers.get(name)
237
237
238 def get_handler_by_esc(self, esc_str):
238 def get_handler_by_esc(self, esc_str):
239 """Get a handler by its escape string."""
239 """Get a handler by its escape string."""
240 return self._esc_handlers.get(esc_str)
240 return self._esc_handlers.get(esc_str)
241
241
242 #-------------------------------------------------------------------------
242 #-------------------------------------------------------------------------
243 # Main prefiltering API
243 # Main prefiltering API
244 #-------------------------------------------------------------------------
244 #-------------------------------------------------------------------------
245
245
246 def prefilter_line_info(self, line_info):
246 def prefilter_line_info(self, line_info):
247 """Prefilter a line that has been converted to a LineInfo object.
247 """Prefilter a line that has been converted to a LineInfo object.
248
248
249 This implements the checker/handler part of the prefilter pipe.
249 This implements the checker/handler part of the prefilter pipe.
250 """
250 """
251 # print "prefilter_line_info: ", line_info
251 # print "prefilter_line_info: ", line_info
252 handler = self.find_handler(line_info)
252 handler = self.find_handler(line_info)
253 return handler.handle(line_info)
253 return handler.handle(line_info)
254
254
255 def find_handler(self, line_info):
255 def find_handler(self, line_info):
256 """Find a handler for the line_info by trying checkers."""
256 """Find a handler for the line_info by trying checkers."""
257 for checker in self.checkers:
257 for checker in self.checkers:
258 if checker.enabled:
258 if checker.enabled:
259 handler = checker.check(line_info)
259 handler = checker.check(line_info)
260 if handler:
260 if handler:
261 return handler
261 return handler
262 return self.get_handler_by_name('normal')
262 return self.get_handler_by_name('normal')
263
263
264 def transform_line(self, line, continue_prompt):
264 def transform_line(self, line, continue_prompt):
265 """Calls the enabled transformers in order of increasing priority."""
265 """Calls the enabled transformers in order of increasing priority."""
266 for transformer in self.transformers:
266 for transformer in self.transformers:
267 if transformer.enabled:
267 if transformer.enabled:
268 line = transformer.transform(line, continue_prompt)
268 line = transformer.transform(line, continue_prompt)
269 return line
269 return line
270
270
271 def prefilter_line(self, line, continue_prompt=False):
271 def prefilter_line(self, line, continue_prompt=False):
272 """Prefilter a single input line as text.
272 """Prefilter a single input line as text.
273
273
274 This method prefilters a single line of text by calling the
274 This method prefilters a single line of text by calling the
275 transformers and then the checkers/handlers.
275 transformers and then the checkers/handlers.
276 """
276 """
277
277
278 # print "prefilter_line: ", line, continue_prompt
278 # print "prefilter_line: ", line, continue_prompt
279 # All handlers *must* return a value, even if it's blank ('').
279 # All handlers *must* return a value, even if it's blank ('').
280
280
281 # save the line away in case we crash, so the post-mortem handler can
281 # save the line away in case we crash, so the post-mortem handler can
282 # record it
282 # record it
283 self.shell._last_input_line = line
283 self.shell._last_input_line = line
284
284
285 if not line:
285 if not line:
286 # Return immediately on purely empty lines, so that if the user
286 # Return immediately on purely empty lines, so that if the user
287 # previously typed some whitespace that started a continuation
287 # previously typed some whitespace that started a continuation
288 # prompt, he can break out of that loop with just an empty line.
288 # prompt, he can break out of that loop with just an empty line.
289 # This is how the default python prompt works.
289 # This is how the default python prompt works.
290 return ''
290 return ''
291
291
292 # At this point, we invoke our transformers.
292 # At this point, we invoke our transformers.
293 if not continue_prompt or (continue_prompt and self.multi_line_specials):
293 if not continue_prompt or (continue_prompt and self.multi_line_specials):
294 line = self.transform_line(line, continue_prompt)
294 line = self.transform_line(line, continue_prompt)
295
295
296 # Now we compute line_info for the checkers and handlers
296 # Now we compute line_info for the checkers and handlers
297 line_info = LineInfo(line, continue_prompt)
297 line_info = LineInfo(line, continue_prompt)
298
298
299 # the input history needs to track even empty lines
299 # the input history needs to track even empty lines
300 stripped = line.strip()
300 stripped = line.strip()
301
301
302 normal_handler = self.get_handler_by_name('normal')
302 normal_handler = self.get_handler_by_name('normal')
303 if not stripped:
303 if not stripped:
304 return normal_handler.handle(line_info)
304 return normal_handler.handle(line_info)
305
305
306 # special handlers are only allowed for single line statements
306 # special handlers are only allowed for single line statements
307 if continue_prompt and not self.multi_line_specials:
307 if continue_prompt and not self.multi_line_specials:
308 return normal_handler.handle(line_info)
308 return normal_handler.handle(line_info)
309
309
310 prefiltered = self.prefilter_line_info(line_info)
310 prefiltered = self.prefilter_line_info(line_info)
311 # print "prefiltered line: %r" % prefiltered
311 # print "prefiltered line: %r" % prefiltered
312 return prefiltered
312 return prefiltered
313
313
314 def prefilter_lines(self, lines, continue_prompt=False):
314 def prefilter_lines(self, lines, continue_prompt=False):
315 """Prefilter multiple input lines of text.
315 """Prefilter multiple input lines of text.
316
316
317 This is the main entry point for prefiltering multiple lines of
317 This is the main entry point for prefiltering multiple lines of
318 input. This simply calls :meth:`prefilter_line` for each line of
318 input. This simply calls :meth:`prefilter_line` for each line of
319 input.
319 input.
320
320
321 This covers cases where there are multiple lines in the user entry,
321 This covers cases where there are multiple lines in the user entry,
322 which is the case when the user goes back to a multiline history
322 which is the case when the user goes back to a multiline history
323 entry and presses enter.
323 entry and presses enter.
324 """
324 """
325 llines = lines.rstrip('\n').split('\n')
325 llines = lines.rstrip('\n').split('\n')
326 # We can get multiple lines in one shot, where multiline input 'blends'
326 # We can get multiple lines in one shot, where multiline input 'blends'
327 # into one line, in cases like recalling from the readline history
327 # into one line, in cases like recalling from the readline history
328 # buffer. We need to make sure that in such cases, we correctly
328 # buffer. We need to make sure that in such cases, we correctly
329 # communicate downstream which line is first and which are continuation
329 # communicate downstream which line is first and which are continuation
330 # ones.
330 # ones.
331 if len(llines) > 1:
331 if len(llines) > 1:
332 out = '\n'.join([self.prefilter_line(line, lnum>0)
332 out = '\n'.join([self.prefilter_line(line, lnum>0)
333 for lnum, line in enumerate(llines) ])
333 for lnum, line in enumerate(llines) ])
334 else:
334 else:
335 out = self.prefilter_line(llines[0], continue_prompt)
335 out = self.prefilter_line(llines[0], continue_prompt)
336
336
337 return out
337 return out
338
338
339 #-----------------------------------------------------------------------------
339 #-----------------------------------------------------------------------------
340 # Prefilter transformers
340 # Prefilter transformers
341 #-----------------------------------------------------------------------------
341 #-----------------------------------------------------------------------------
342
342
343
343
344 class PrefilterTransformer(Configurable):
344 class PrefilterTransformer(Configurable):
345 """Transform a line of user input."""
345 """Transform a line of user input."""
346
346
347 priority = Integer(100).tag(config=True)
347 priority = Integer(100).tag(config=True)
348 # Transformers don't currently use shell or prefilter_manager, but as we
348 # Transformers don't currently use shell or prefilter_manager, but as we
349 # move away from checkers and handlers, they will need them.
349 # move away from checkers and handlers, they will need them.
350 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
350 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
351 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
351 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
352 enabled = Bool(True).tag(config=True)
352 enabled = Bool(True).tag(config=True)
353
353
354 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
354 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
355 super(PrefilterTransformer, self).__init__(
355 super(PrefilterTransformer, self).__init__(
356 shell=shell, prefilter_manager=prefilter_manager, **kwargs
356 shell=shell, prefilter_manager=prefilter_manager, **kwargs
357 )
357 )
358 self.prefilter_manager.register_transformer(self)
358 self.prefilter_manager.register_transformer(self)
359
359
360 def transform(self, line, continue_prompt):
360 def transform(self, line, continue_prompt):
361 """Transform a line, returning the new one."""
361 """Transform a line, returning the new one."""
362 return None
362 return None
363
363
364 def __repr__(self):
364 def __repr__(self):
365 return "<%s(priority=%r, enabled=%r)>" % (
365 return "<%s(priority=%r, enabled=%r)>" % (
366 self.__class__.__name__, self.priority, self.enabled)
366 self.__class__.__name__, self.priority, self.enabled)
367
367
368
368
369 #-----------------------------------------------------------------------------
369 #-----------------------------------------------------------------------------
370 # Prefilter checkers
370 # Prefilter checkers
371 #-----------------------------------------------------------------------------
371 #-----------------------------------------------------------------------------
372
372
373
373
374 class PrefilterChecker(Configurable):
374 class PrefilterChecker(Configurable):
375 """Inspect an input line and return a handler for that line."""
375 """Inspect an input line and return a handler for that line."""
376
376
377 priority = Integer(100).tag(config=True)
377 priority = Integer(100).tag(config=True)
378 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
378 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
379 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
379 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
380 enabled = Bool(True).tag(config=True)
380 enabled = Bool(True).tag(config=True)
381
381
382 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
382 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
383 super(PrefilterChecker, self).__init__(
383 super(PrefilterChecker, self).__init__(
384 shell=shell, prefilter_manager=prefilter_manager, **kwargs
384 shell=shell, prefilter_manager=prefilter_manager, **kwargs
385 )
385 )
386 self.prefilter_manager.register_checker(self)
386 self.prefilter_manager.register_checker(self)
387
387
388 def check(self, line_info):
388 def check(self, line_info):
389 """Inspect line_info and return a handler instance or None."""
389 """Inspect line_info and return a handler instance or None."""
390 return None
390 return None
391
391
392 def __repr__(self):
392 def __repr__(self):
393 return "<%s(priority=%r, enabled=%r)>" % (
393 return "<%s(priority=%r, enabled=%r)>" % (
394 self.__class__.__name__, self.priority, self.enabled)
394 self.__class__.__name__, self.priority, self.enabled)
395
395
396
396
397 class EmacsChecker(PrefilterChecker):
397 class EmacsChecker(PrefilterChecker):
398
398
399 priority = Integer(100).tag(config=True)
399 priority = Integer(100).tag(config=True)
400 enabled = Bool(False).tag(config=True)
400 enabled = Bool(False).tag(config=True)
401
401
402 def check(self, line_info):
402 def check(self, line_info):
403 "Emacs ipython-mode tags certain input lines."
403 "Emacs ipython-mode tags certain input lines."
404 if line_info.line.endswith('# PYTHON-MODE'):
404 if line_info.line.endswith('# PYTHON-MODE'):
405 return self.prefilter_manager.get_handler_by_name('emacs')
405 return self.prefilter_manager.get_handler_by_name('emacs')
406 else:
406 else:
407 return None
407 return None
408
408
409
409
410 class MacroChecker(PrefilterChecker):
410 class MacroChecker(PrefilterChecker):
411
411
412 priority = Integer(250).tag(config=True)
412 priority = Integer(250).tag(config=True)
413
413
414 def check(self, line_info):
414 def check(self, line_info):
415 obj = self.shell.user_ns.get(line_info.ifun)
415 obj = self.shell.user_ns.get(line_info.ifun)
416 if isinstance(obj, Macro):
416 if isinstance(obj, Macro):
417 return self.prefilter_manager.get_handler_by_name('macro')
417 return self.prefilter_manager.get_handler_by_name('macro')
418 else:
418 else:
419 return None
419 return None
420
420
421
421
422 class IPyAutocallChecker(PrefilterChecker):
422 class IPyAutocallChecker(PrefilterChecker):
423
423
424 priority = Integer(300).tag(config=True)
424 priority = Integer(300).tag(config=True)
425
425
426 def check(self, line_info):
426 def check(self, line_info):
427 "Instances of IPyAutocall in user_ns get autocalled immediately"
427 "Instances of IPyAutocall in user_ns get autocalled immediately"
428 obj = self.shell.user_ns.get(line_info.ifun, None)
428 obj = self.shell.user_ns.get(line_info.ifun, None)
429 if isinstance(obj, IPyAutocall):
429 if isinstance(obj, IPyAutocall):
430 obj.set_ip(self.shell)
430 obj.set_ip(self.shell)
431 return self.prefilter_manager.get_handler_by_name('auto')
431 return self.prefilter_manager.get_handler_by_name('auto')
432 else:
432 else:
433 return None
433 return None
434
434
435
435
436 class AssignmentChecker(PrefilterChecker):
436 class AssignmentChecker(PrefilterChecker):
437
437
438 priority = Integer(600).tag(config=True)
438 priority = Integer(600).tag(config=True)
439
439
440 def check(self, line_info):
440 def check(self, line_info):
441 """Check to see if user is assigning to a var for the first time, in
441 """Check to see if user is assigning to a var for the first time, in
442 which case we want to avoid any sort of automagic / autocall games.
442 which case we want to avoid any sort of automagic / autocall games.
443
443
444 This allows users to assign to either alias or magic names true python
444 This allows users to assign to either alias or magic names true python
445 variables (the magic/alias systems always take second seat to true
445 variables (the magic/alias systems always take second seat to true
446 python code). E.g. ls='hi', or ls,that=1,2"""
446 python code). E.g. ls='hi', or ls,that=1,2"""
447 if line_info.the_rest:
447 if line_info.the_rest:
448 if line_info.the_rest[0] in '=,':
448 if line_info.the_rest[0] in '=,':
449 return self.prefilter_manager.get_handler_by_name('normal')
449 return self.prefilter_manager.get_handler_by_name('normal')
450 else:
450 else:
451 return None
451 return None
452
452
453
453
454 class AutoMagicChecker(PrefilterChecker):
454 class AutoMagicChecker(PrefilterChecker):
455
455
456 priority = Integer(700).tag(config=True)
456 priority = Integer(700).tag(config=True)
457
457
458 def check(self, line_info):
458 def check(self, line_info):
459 """If the ifun is magic, and automagic is on, run it. Note: normal,
459 """If the ifun is magic, and automagic is on, run it. Note: normal,
460 non-auto magic would already have been triggered via '%' in
460 non-auto magic would already have been triggered via '%' in
461 check_esc_chars. This just checks for automagic. Also, before
461 check_esc_chars. This just checks for automagic. Also, before
462 triggering the magic handler, make sure that there is nothing in the
462 triggering the magic handler, make sure that there is nothing in the
463 user namespace which could shadow it."""
463 user namespace which could shadow it."""
464 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
464 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
465 return None
465 return None
466
466
467 # We have a likely magic method. Make sure we should actually call it.
467 # We have a likely magic method. Make sure we should actually call it.
468 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
468 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
469 return None
469 return None
470
470
471 head = line_info.ifun.split('.',1)[0]
471 head = line_info.ifun.split('.',1)[0]
472 if is_shadowed(head, self.shell):
472 if is_shadowed(head, self.shell):
473 return None
473 return None
474
474
475 return self.prefilter_manager.get_handler_by_name('magic')
475 return self.prefilter_manager.get_handler_by_name('magic')
476
476
477
477
478 class PythonOpsChecker(PrefilterChecker):
478 class PythonOpsChecker(PrefilterChecker):
479
479
480 priority = Integer(900).tag(config=True)
480 priority = Integer(900).tag(config=True)
481
481
482 def check(self, line_info):
482 def check(self, line_info):
483 """If the 'rest' of the line begins with a function call or pretty much
483 """If the 'rest' of the line begins with a function call or pretty much
484 any python operator, we should simply execute the line (regardless of
484 any python operator, we should simply execute the line (regardless of
485 whether or not there's a possible autocall expansion). This avoids
485 whether or not there's a possible autocall expansion). This avoids
486 spurious (and very confusing) geattr() accesses."""
486 spurious (and very confusing) geattr() accesses."""
487 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
487 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
488 return self.prefilter_manager.get_handler_by_name('normal')
488 return self.prefilter_manager.get_handler_by_name('normal')
489 else:
489 else:
490 return None
490 return None
491
491
492
492
493 class AutocallChecker(PrefilterChecker):
493 class AutocallChecker(PrefilterChecker):
494
494
495 priority = Integer(1000).tag(config=True)
495 priority = Integer(1000).tag(config=True)
496
496
497 function_name_regexp = CRegExp(re_fun_name,
497 function_name_regexp = CRegExp(re_fun_name,
498 help="RegExp to identify potential function names."
498 help="RegExp to identify potential function names."
499 ).tag(config=True)
499 ).tag(config=True)
500 exclude_regexp = CRegExp(re_exclude_auto,
500 exclude_regexp = CRegExp(re_exclude_auto,
501 help="RegExp to exclude strings with this start from autocalling."
501 help="RegExp to exclude strings with this start from autocalling."
502 ).tag(config=True)
502 ).tag(config=True)
503
503
504 def check(self, line_info):
504 def check(self, line_info):
505 "Check if the initial word/function is callable and autocall is on."
505 "Check if the initial word/function is callable and autocall is on."
506 if not self.shell.autocall:
506 if not self.shell.autocall:
507 return None
507 return None
508
508
509 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
509 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
510 if not oinfo['found']:
510 if not oinfo['found']:
511 return None
511 return None
512
512
513 ignored_funs = ['b', 'f', 'r', 'u', 'br', 'rb', 'fr', 'rf']
513 ignored_funs = ['b', 'f', 'r', 'u', 'br', 'rb', 'fr', 'rf']
514 ifun = line_info.ifun
514 ifun = line_info.ifun
515 line = line_info.line
515 line = line_info.line
516 if ifun.lower() in ignored_funs and (line.startswith(ifun + "'") or line.startswith(ifun + '"')):
516 if ifun.lower() in ignored_funs and (line.startswith(ifun + "'") or line.startswith(ifun + '"')):
517 return None
517 return None
518
518
519 if callable(oinfo['obj']) \
519 if callable(oinfo['obj']) \
520 and (not self.exclude_regexp.match(line_info.the_rest)) \
520 and (not self.exclude_regexp.match(line_info.the_rest)) \
521 and self.function_name_regexp.match(line_info.ifun):
521 and self.function_name_regexp.match(line_info.ifun):
522 return self.prefilter_manager.get_handler_by_name('auto')
522 return self.prefilter_manager.get_handler_by_name('auto')
523 else:
523 else:
524 return None
524 return None
525
525
526
526
527 #-----------------------------------------------------------------------------
527 #-----------------------------------------------------------------------------
528 # Prefilter handlers
528 # Prefilter handlers
529 #-----------------------------------------------------------------------------
529 #-----------------------------------------------------------------------------
530
530
531
531
532 class PrefilterHandler(Configurable):
532 class PrefilterHandler(Configurable):
533
533
534 handler_name = Unicode('normal')
534 handler_name = Unicode('normal')
535 esc_strings = List([])
535 esc_strings = List([])
536 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
536 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
537 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
537 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
538
538
539 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
539 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
540 super(PrefilterHandler, self).__init__(
540 super(PrefilterHandler, self).__init__(
541 shell=shell, prefilter_manager=prefilter_manager, **kwargs
541 shell=shell, prefilter_manager=prefilter_manager, **kwargs
542 )
542 )
543 self.prefilter_manager.register_handler(
543 self.prefilter_manager.register_handler(
544 self.handler_name,
544 self.handler_name,
545 self,
545 self,
546 self.esc_strings
546 self.esc_strings
547 )
547 )
548
548
549 def handle(self, line_info):
549 def handle(self, line_info):
550 # print "normal: ", line_info
550 # print "normal: ", line_info
551 """Handle normal input lines. Use as a template for handlers."""
551 """Handle normal input lines. Use as a template for handlers."""
552
552
553 # With autoindent on, we need some way to exit the input loop, and I
553 # With autoindent on, we need some way to exit the input loop, and I
554 # don't want to force the user to have to backspace all the way to
554 # don't want to force the user to have to backspace all the way to
555 # clear the line. The rule will be in this case, that either two
555 # clear the line. The rule will be in this case, that either two
556 # lines of pure whitespace in a row, or a line of pure whitespace but
556 # lines of pure whitespace in a row, or a line of pure whitespace but
557 # of a size different to the indent level, will exit the input loop.
557 # of a size different to the indent level, will exit the input loop.
558 line = line_info.line
558 line = line_info.line
559 continue_prompt = line_info.continue_prompt
559 continue_prompt = line_info.continue_prompt
560
560
561 if (continue_prompt and
561 if (continue_prompt and
562 self.shell.autoindent and
562 self.shell.autoindent and
563 line.isspace() and
563 line.isspace() and
564 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
564 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
565 line = ''
565 line = ''
566
566
567 return line
567 return line
568
568
569 def __str__(self):
569 def __str__(self):
570 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
570 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
571
571
572
572
573 class MacroHandler(PrefilterHandler):
573 class MacroHandler(PrefilterHandler):
574 handler_name = Unicode("macro")
574 handler_name = Unicode("macro")
575
575
576 def handle(self, line_info):
576 def handle(self, line_info):
577 obj = self.shell.user_ns.get(line_info.ifun)
577 obj = self.shell.user_ns.get(line_info.ifun)
578 pre_space = line_info.pre_whitespace
578 pre_space = line_info.pre_whitespace
579 line_sep = "\n" + pre_space
579 line_sep = "\n" + pre_space
580 return pre_space + line_sep.join(obj.value.splitlines())
580 return pre_space + line_sep.join(obj.value.splitlines())
581
581
582
582
583 class MagicHandler(PrefilterHandler):
583 class MagicHandler(PrefilterHandler):
584
584
585 handler_name = Unicode('magic')
585 handler_name = Unicode('magic')
586 esc_strings = List([ESC_MAGIC])
586 esc_strings = List([ESC_MAGIC])
587
587
588 def handle(self, line_info):
588 def handle(self, line_info):
589 """Execute magic functions."""
589 """Execute magic functions."""
590 ifun = line_info.ifun
590 ifun = line_info.ifun
591 the_rest = line_info.the_rest
591 the_rest = line_info.the_rest
592 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
592 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
593 t_arg_s = ifun + " " + the_rest
593 t_arg_s = ifun + " " + the_rest
594 t_magic_name, _, t_magic_arg_s = t_arg_s.partition(' ')
594 t_magic_name, _, t_magic_arg_s = t_arg_s.partition(' ')
595 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
595 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
596 cmd = '%sget_ipython().run_line_magic(%r, %r)' % (line_info.pre_whitespace, t_magic_name, t_magic_arg_s)
596 cmd = '%sget_ipython().run_line_magic(%r, %r)' % (line_info.pre_whitespace, t_magic_name, t_magic_arg_s)
597 return cmd
597 return cmd
598
598
599
599
600 class AutoHandler(PrefilterHandler):
600 class AutoHandler(PrefilterHandler):
601
601
602 handler_name = Unicode('auto')
602 handler_name = Unicode('auto')
603 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
603 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
604
604
605 def handle(self, line_info):
605 def handle(self, line_info):
606 """Handle lines which can be auto-executed, quoting if requested."""
606 """Handle lines which can be auto-executed, quoting if requested."""
607 line = line_info.line
607 line = line_info.line
608 ifun = line_info.ifun
608 ifun = line_info.ifun
609 the_rest = line_info.the_rest
609 the_rest = line_info.the_rest
610 esc = line_info.esc
610 esc = line_info.esc
611 continue_prompt = line_info.continue_prompt
611 continue_prompt = line_info.continue_prompt
612 obj = line_info.ofind(self.shell)['obj']
612 obj = line_info.ofind(self.shell)['obj']
613
613
614 # This should only be active for single-line input!
614 # This should only be active for single-line input!
615 if continue_prompt:
615 if continue_prompt:
616 return line
616 return line
617
617
618 force_auto = isinstance(obj, IPyAutocall)
618 force_auto = isinstance(obj, IPyAutocall)
619
619
620 # User objects sometimes raise exceptions on attribute access other
620 # User objects sometimes raise exceptions on attribute access other
621 # than AttributeError (we've seen it in the past), so it's safest to be
621 # than AttributeError (we've seen it in the past), so it's safest to be
622 # ultra-conservative here and catch all.
622 # ultra-conservative here and catch all.
623 try:
623 try:
624 auto_rewrite = obj.rewrite
624 auto_rewrite = obj.rewrite
625 except Exception:
625 except Exception:
626 auto_rewrite = True
626 auto_rewrite = True
627
627
628 if esc == ESC_QUOTE:
628 if esc == ESC_QUOTE:
629 # Auto-quote splitting on whitespace
629 # Auto-quote splitting on whitespace
630 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
630 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
631 elif esc == ESC_QUOTE2:
631 elif esc == ESC_QUOTE2:
632 # Auto-quote whole string
632 # Auto-quote whole string
633 newcmd = '%s("%s")' % (ifun,the_rest)
633 newcmd = '%s("%s")' % (ifun,the_rest)
634 elif esc == ESC_PAREN:
634 elif esc == ESC_PAREN:
635 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
635 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
636 else:
636 else:
637 # Auto-paren.
637 # Auto-paren.
638 if force_auto:
638 if force_auto:
639 # Don't rewrite if it is already a call.
639 # Don't rewrite if it is already a call.
640 do_rewrite = not the_rest.startswith('(')
640 do_rewrite = not the_rest.startswith('(')
641 else:
641 else:
642 if not the_rest:
642 if not the_rest:
643 # We only apply it to argument-less calls if the autocall
643 # We only apply it to argument-less calls if the autocall
644 # parameter is set to 2.
644 # parameter is set to 2.
645 do_rewrite = (self.shell.autocall >= 2)
645 do_rewrite = (self.shell.autocall >= 2)
646 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
646 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
647 # Don't autocall in this case: item access for an object
647 # Don't autocall in this case: item access for an object
648 # which is BOTH callable and implements __getitem__.
648 # which is BOTH callable and implements __getitem__.
649 do_rewrite = False
649 do_rewrite = False
650 else:
650 else:
651 do_rewrite = True
651 do_rewrite = True
652
652
653 # Figure out the rewritten command
653 # Figure out the rewritten command
654 if do_rewrite:
654 if do_rewrite:
655 if the_rest.endswith(';'):
655 if the_rest.endswith(';'):
656 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
656 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
657 else:
657 else:
658 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
658 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
659 else:
659 else:
660 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
660 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
661 return normal_handler.handle(line_info)
661 return normal_handler.handle(line_info)
662
662
663 # Display the rewritten call
663 # Display the rewritten call
664 if auto_rewrite:
664 if auto_rewrite:
665 self.shell.auto_rewrite_input(newcmd)
665 self.shell.auto_rewrite_input(newcmd)
666
666
667 return newcmd
667 return newcmd
668
668
669
669
670 class EmacsHandler(PrefilterHandler):
670 class EmacsHandler(PrefilterHandler):
671
671
672 handler_name = Unicode('emacs')
672 handler_name = Unicode('emacs')
673 esc_strings = List([])
673 esc_strings = List([])
674
674
675 def handle(self, line_info):
675 def handle(self, line_info):
676 """Handle input lines marked by python-mode."""
676 """Handle input lines marked by python-mode."""
677
677
678 # Currently, nothing is done. Later more functionality can be added
678 # Currently, nothing is done. Later more functionality can be added
679 # here if needed.
679 # here if needed.
680
680
681 # The input cache shouldn't be updated
681 # The input cache shouldn't be updated
682 return line_info.line
682 return line_info.line
683
683
684
684
685 #-----------------------------------------------------------------------------
685 #-----------------------------------------------------------------------------
686 # Defaults
686 # Defaults
687 #-----------------------------------------------------------------------------
687 #-----------------------------------------------------------------------------
688
688
689
689
690 _default_transformers = [
690 _default_transformers = [
691 ]
691 ]
692
692
693 _default_checkers = [
693 _default_checkers = [
694 EmacsChecker,
694 EmacsChecker,
695 MacroChecker,
695 MacroChecker,
696 IPyAutocallChecker,
696 IPyAutocallChecker,
697 AssignmentChecker,
697 AssignmentChecker,
698 AutoMagicChecker,
698 AutoMagicChecker,
699 PythonOpsChecker,
699 PythonOpsChecker,
700 AutocallChecker
700 AutocallChecker
701 ]
701 ]
702
702
703 _default_handlers = [
703 _default_handlers = [
704 PrefilterHandler,
704 PrefilterHandler,
705 MacroHandler,
705 MacroHandler,
706 MagicHandler,
706 MagicHandler,
707 AutoHandler,
707 AutoHandler,
708 EmacsHandler
708 EmacsHandler
709 ]
709 ]
@@ -1,494 +1,495 b''
1 import tokenize
1 import tokenize
2 import nose.tools as nt
2 import nose.tools as nt
3
3
4 from IPython.testing import tools as tt
4 from IPython.testing import tools as tt
5 from IPython.utils import py3compat
5 from IPython.utils import py3compat
6 u_fmt = py3compat.u_format
6 u_fmt = py3compat.u_format
7
7
8 from IPython.core import inputtransformer as ipt
8 from IPython.core import inputtransformer as ipt
9
9
10 def transform_and_reset(transformer):
10 def transform_and_reset(transformer):
11 transformer = transformer()
11 transformer = transformer()
12 def transform(inp):
12 def transform(inp):
13 try:
13 try:
14 return transformer.push(inp)
14 return transformer.push(inp)
15 finally:
15 finally:
16 transformer.reset()
16 transformer.reset()
17
17
18 return transform
18 return transform
19
19
20 # Transformer tests
20 # Transformer tests
21 def transform_checker(tests, transformer, **kwargs):
21 def transform_checker(tests, transformer, **kwargs):
22 """Utility to loop over test inputs"""
22 """Utility to loop over test inputs"""
23 transformer = transformer(**kwargs)
23 transformer = transformer(**kwargs)
24 try:
24 try:
25 for inp, tr in tests:
25 for inp, tr in tests:
26 if inp is None:
26 if inp is None:
27 out = transformer.reset()
27 out = transformer.reset()
28 else:
28 else:
29 out = transformer.push(inp)
29 out = transformer.push(inp)
30 nt.assert_equal(out, tr)
30 nt.assert_equal(out, tr)
31 finally:
31 finally:
32 transformer.reset()
32 transformer.reset()
33
33
34 # Data for all the syntax tests in the form of lists of pairs of
34 # Data for all the syntax tests in the form of lists of pairs of
35 # raw/transformed input. We store it here as a global dict so that we can use
35 # raw/transformed input. We store it here as a global dict so that we can use
36 # it both within single-function tests and also to validate the behavior of the
36 # it both within single-function tests and also to validate the behavior of the
37 # larger objects
37 # larger objects
38
38
39 syntax = \
39 syntax = \
40 dict(assign_system =
40 dict(assign_system =
41 [(i,py3compat.u_format(o)) for i,o in \
41 [(i,py3compat.u_format(o)) for i,o in \
42 [(u'a =! ls', "a = get_ipython().getoutput('ls')"),
42 [(u'a =! ls', "a = get_ipython().getoutput('ls')"),
43 (u'b = !ls', "b = get_ipython().getoutput('ls')"),
43 (u'b = !ls', "b = get_ipython().getoutput('ls')"),
44 (u'c= !ls', "c = get_ipython().getoutput('ls')"),
44 (u'c= !ls', "c = get_ipython().getoutput('ls')"),
45 (u'd == !ls', u'd == !ls'), # Invalid syntax, but we leave == alone.
45 (u'd == !ls', u'd == !ls'), # Invalid syntax, but we leave == alone.
46 ('x=1', 'x=1'), # normal input is unmodified
46 ('x=1', 'x=1'), # normal input is unmodified
47 (' ',' '), # blank lines are kept intact
47 (' ',' '), # blank lines are kept intact
48 # Tuple unpacking
48 # Tuple unpacking
49 (u"a, b = !echo 'a\\nb'", u"a, b = get_ipython().getoutput(\"echo 'a\\\\nb'\")"),
49 (u"a, b = !echo 'a\\nb'", u"a, b = get_ipython().getoutput(\"echo 'a\\\\nb'\")"),
50 (u"a,= !echo 'a'", u"a, = get_ipython().getoutput(\"echo 'a'\")"),
50 (u"a,= !echo 'a'", u"a, = get_ipython().getoutput(\"echo 'a'\")"),
51 (u"a, *bc = !echo 'a\\nb\\nc'", u"a, *bc = get_ipython().getoutput(\"echo 'a\\\\nb\\\\nc'\")"),
51 (u"a, *bc = !echo 'a\\nb\\nc'", u"a, *bc = get_ipython().getoutput(\"echo 'a\\\\nb\\\\nc'\")"),
52 # Tuple unpacking with regular Python expressions, not our syntax.
52 # Tuple unpacking with regular Python expressions, not our syntax.
53 (u"a, b = range(2)", u"a, b = range(2)"),
53 (u"a, b = range(2)", u"a, b = range(2)"),
54 (u"a, = range(1)", u"a, = range(1)"),
54 (u"a, = range(1)", u"a, = range(1)"),
55 (u"a, *bc = range(3)", u"a, *bc = range(3)"),
55 (u"a, *bc = range(3)", u"a, *bc = range(3)"),
56 ]],
56 ]],
57
57
58 assign_magic =
58 assign_magic =
59 [(i,py3compat.u_format(o)) for i,o in \
59 [(i,py3compat.u_format(o)) for i,o in \
60 [(u'a =% who', "a = get_ipython().run_line_magic('who', '')"),
60 [(u'a =% who', "a = get_ipython().run_line_magic('who', '')"),
61 (u'b = %who', "b = get_ipython().run_line_magic('who', '')"),
61 (u'b = %who', "b = get_ipython().run_line_magic('who', '')"),
62 (u'c= %ls', "c = get_ipython().run_line_magic('ls', '')"),
62 (u'c= %ls', "c = get_ipython().run_line_magic('ls', '')"),
63 (u'd == %ls', u'd == %ls'), # Invalid syntax, but we leave == alone.
63 (u'd == %ls', u'd == %ls'), # Invalid syntax, but we leave == alone.
64 ('x=1', 'x=1'), # normal input is unmodified
64 ('x=1', 'x=1'), # normal input is unmodified
65 (' ',' '), # blank lines are kept intact
65 (' ',' '), # blank lines are kept intact
66 (u"a, b = %foo", u"a, b = get_ipython().run_line_magic('foo', '')"),
66 (u"a, b = %foo", u"a, b = get_ipython().run_line_magic('foo', '')"),
67 ]],
67 ]],
68
68
69 classic_prompt =
69 classic_prompt =
70 [('>>> x=1', 'x=1'),
70 [('>>> x=1', 'x=1'),
71 ('x=1', 'x=1'), # normal input is unmodified
71 ('x=1', 'x=1'), # normal input is unmodified
72 (' ', ' '), # blank lines are kept intact
72 (' ', ' '), # blank lines are kept intact
73 ],
73 ],
74
74
75 ipy_prompt =
75 ipy_prompt =
76 [('In [1]: x=1', 'x=1'),
76 [('In [1]: x=1', 'x=1'),
77 ('x=1', 'x=1'), # normal input is unmodified
77 ('x=1', 'x=1'), # normal input is unmodified
78 (' ',' '), # blank lines are kept intact
78 (' ',' '), # blank lines are kept intact
79 ],
79 ],
80
80
81 # Tests for the escape transformer to leave normal code alone
81 # Tests for the escape transformer to leave normal code alone
82 escaped_noesc =
82 escaped_noesc =
83 [ (' ', ' '),
83 [ (' ', ' '),
84 ('x=1', 'x=1'),
84 ('x=1', 'x=1'),
85 ],
85 ],
86
86
87 # System calls
87 # System calls
88 escaped_shell =
88 escaped_shell =
89 [(i,py3compat.u_format(o)) for i,o in \
89 [(i,py3compat.u_format(o)) for i,o in \
90 [ (u'!ls', "get_ipython().system('ls')"),
90 [ (u'!ls', "get_ipython().system('ls')"),
91 # Double-escape shell, this means to capture the output of the
91 # Double-escape shell, this means to capture the output of the
92 # subprocess and return it
92 # subprocess and return it
93 (u'!!ls', "get_ipython().getoutput('ls')"),
93 (u'!!ls', "get_ipython().getoutput('ls')"),
94 ]],
94 ]],
95
95
96 # Help/object info
96 # Help/object info
97 escaped_help =
97 escaped_help =
98 [(i,py3compat.u_format(o)) for i,o in \
98 [(i,py3compat.u_format(o)) for i,o in \
99 [ (u'?', 'get_ipython().show_usage()'),
99 [ (u'?', 'get_ipython().show_usage()'),
100 (u'?x1', "get_ipython().run_line_magic('pinfo', 'x1')"),
100 (u'?x1', "get_ipython().run_line_magic('pinfo', 'x1')"),
101 (u'??x2', "get_ipython().run_line_magic('pinfo2', 'x2')"),
101 (u'??x2', "get_ipython().run_line_magic('pinfo2', 'x2')"),
102 (u'?a.*s', "get_ipython().run_line_magic('psearch', 'a.*s')"),
102 (u'?a.*s', "get_ipython().run_line_magic('psearch', 'a.*s')"),
103 (u'?%hist1', "get_ipython().run_line_magic('pinfo', '%hist1')"),
103 (u'?%hist1', "get_ipython().run_line_magic('pinfo', '%hist1')"),
104 (u'?%%hist2', "get_ipython().run_line_magic('pinfo', '%%hist2')"),
104 (u'?%%hist2', "get_ipython().run_line_magic('pinfo', '%%hist2')"),
105 (u'?abc = qwe', "get_ipython().run_line_magic('pinfo', 'abc')"),
105 (u'?abc = qwe', "get_ipython().run_line_magic('pinfo', 'abc')"),
106 ]],
106 ]],
107
107
108 end_help =
108 end_help =
109 [(i,py3compat.u_format(o)) for i,o in \
109 [(i,py3compat.u_format(o)) for i,o in \
110 [ (u'x3?', "get_ipython().run_line_magic('pinfo', 'x3')"),
110 [ (u'x3?', "get_ipython().run_line_magic('pinfo', 'x3')"),
111 (u'x4??', "get_ipython().run_line_magic('pinfo2', 'x4')"),
111 (u'x4??', "get_ipython().run_line_magic('pinfo2', 'x4')"),
112 (u'%hist1?', "get_ipython().run_line_magic('pinfo', '%hist1')"),
112 (u'%hist1?', "get_ipython().run_line_magic('pinfo', '%hist1')"),
113 (u'%hist2??', "get_ipython().run_line_magic('pinfo2', '%hist2')"),
113 (u'%hist2??', "get_ipython().run_line_magic('pinfo2', '%hist2')"),
114 (u'%%hist3?', "get_ipython().run_line_magic('pinfo', '%%hist3')"),
114 (u'%%hist3?', "get_ipython().run_line_magic('pinfo', '%%hist3')"),
115 (u'%%hist4??', "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
115 (u'%%hist4??', "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
116 (u'π.foo?', "get_ipython().run_line_magic('pinfo', 'π.foo')"),
116 (u'f*?', "get_ipython().run_line_magic('psearch', 'f*')"),
117 (u'f*?', "get_ipython().run_line_magic('psearch', 'f*')"),
117 (u'ax.*aspe*?', "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
118 (u'ax.*aspe*?', "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
118 (u'a = abc?', "get_ipython().set_next_input('a = abc');"
119 (u'a = abc?', "get_ipython().set_next_input('a = abc');"
119 "get_ipython().run_line_magic('pinfo', 'abc')"),
120 "get_ipython().run_line_magic('pinfo', 'abc')"),
120 (u'a = abc.qe??', "get_ipython().set_next_input('a = abc.qe');"
121 (u'a = abc.qe??', "get_ipython().set_next_input('a = abc.qe');"
121 "get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
122 "get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
122 (u'a = *.items?', "get_ipython().set_next_input('a = *.items');"
123 (u'a = *.items?', "get_ipython().set_next_input('a = *.items');"
123 "get_ipython().run_line_magic('psearch', '*.items')"),
124 "get_ipython().run_line_magic('psearch', '*.items')"),
124 (u'plot(a?', "get_ipython().set_next_input('plot(a');"
125 (u'plot(a?', "get_ipython().set_next_input('plot(a');"
125 "get_ipython().run_line_magic('pinfo', 'a')"),
126 "get_ipython().run_line_magic('pinfo', 'a')"),
126 (u'a*2 #comment?', 'a*2 #comment?'),
127 (u'a*2 #comment?', 'a*2 #comment?'),
127 ]],
128 ]],
128
129
129 # Explicit magic calls
130 # Explicit magic calls
130 escaped_magic =
131 escaped_magic =
131 [(i,py3compat.u_format(o)) for i,o in \
132 [(i,py3compat.u_format(o)) for i,o in \
132 [ (u'%cd', "get_ipython().run_line_magic('cd', '')"),
133 [ (u'%cd', "get_ipython().run_line_magic('cd', '')"),
133 (u'%cd /home', "get_ipython().run_line_magic('cd', '/home')"),
134 (u'%cd /home', "get_ipython().run_line_magic('cd', '/home')"),
134 # Backslashes need to be escaped.
135 # Backslashes need to be escaped.
135 (u'%cd C:\\User', "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
136 (u'%cd C:\\User', "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
136 (u' %magic', " get_ipython().run_line_magic('magic', '')"),
137 (u' %magic', " get_ipython().run_line_magic('magic', '')"),
137 ]],
138 ]],
138
139
139 # Quoting with separate arguments
140 # Quoting with separate arguments
140 escaped_quote =
141 escaped_quote =
141 [ (',f', 'f("")'),
142 [ (',f', 'f("")'),
142 (',f x', 'f("x")'),
143 (',f x', 'f("x")'),
143 (' ,f y', ' f("y")'),
144 (' ,f y', ' f("y")'),
144 (',f a b', 'f("a", "b")'),
145 (',f a b', 'f("a", "b")'),
145 ],
146 ],
146
147
147 # Quoting with single argument
148 # Quoting with single argument
148 escaped_quote2 =
149 escaped_quote2 =
149 [ (';f', 'f("")'),
150 [ (';f', 'f("")'),
150 (';f x', 'f("x")'),
151 (';f x', 'f("x")'),
151 (' ;f y', ' f("y")'),
152 (' ;f y', ' f("y")'),
152 (';f a b', 'f("a b")'),
153 (';f a b', 'f("a b")'),
153 ],
154 ],
154
155
155 # Simply apply parens
156 # Simply apply parens
156 escaped_paren =
157 escaped_paren =
157 [ ('/f', 'f()'),
158 [ ('/f', 'f()'),
158 ('/f x', 'f(x)'),
159 ('/f x', 'f(x)'),
159 (' /f y', ' f(y)'),
160 (' /f y', ' f(y)'),
160 ('/f a b', 'f(a, b)'),
161 ('/f a b', 'f(a, b)'),
161 ],
162 ],
162
163
163 # Check that we transform prompts before other transforms
164 # Check that we transform prompts before other transforms
164 mixed =
165 mixed =
165 [(i,py3compat.u_format(o)) for i,o in \
166 [(i,py3compat.u_format(o)) for i,o in \
166 [ (u'In [1]: %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
167 [ (u'In [1]: %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
167 (u'>>> %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
168 (u'>>> %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
168 (u'In [2]: !ls', "get_ipython().system('ls')"),
169 (u'In [2]: !ls', "get_ipython().system('ls')"),
169 (u'In [3]: abs?', "get_ipython().run_line_magic('pinfo', 'abs')"),
170 (u'In [3]: abs?', "get_ipython().run_line_magic('pinfo', 'abs')"),
170 (u'In [4]: b = %who', "b = get_ipython().run_line_magic('who', '')"),
171 (u'In [4]: b = %who', "b = get_ipython().run_line_magic('who', '')"),
171 ]],
172 ]],
172 )
173 )
173
174
174 # multiline syntax examples. Each of these should be a list of lists, with
175 # multiline syntax examples. Each of these should be a list of lists, with
175 # each entry itself having pairs of raw/transformed input. The union (with
176 # each entry itself having pairs of raw/transformed input. The union (with
176 # '\n'.join() of the transformed inputs is what the splitter should produce
177 # '\n'.join() of the transformed inputs is what the splitter should produce
177 # when fed the raw lines one at a time via push.
178 # when fed the raw lines one at a time via push.
178 syntax_ml = \
179 syntax_ml = \
179 dict(classic_prompt =
180 dict(classic_prompt =
180 [ [('>>> for i in range(10):','for i in range(10):'),
181 [ [('>>> for i in range(10):','for i in range(10):'),
181 ('... print i',' print i'),
182 ('... print i',' print i'),
182 ('... ', ''),
183 ('... ', ''),
183 ],
184 ],
184 [('>>> a="""','a="""'),
185 [('>>> a="""','a="""'),
185 ('... 123"""','123"""'),
186 ('... 123"""','123"""'),
186 ],
187 ],
187 [('a="""','a="""'),
188 [('a="""','a="""'),
188 ('... 123','123'),
189 ('... 123','123'),
189 ('... 456"""','456"""'),
190 ('... 456"""','456"""'),
190 ],
191 ],
191 [('a="""','a="""'),
192 [('a="""','a="""'),
192 ('>>> 123','123'),
193 ('>>> 123','123'),
193 ('... 456"""','456"""'),
194 ('... 456"""','456"""'),
194 ],
195 ],
195 [('a="""','a="""'),
196 [('a="""','a="""'),
196 ('123','123'),
197 ('123','123'),
197 ('... 456"""','... 456"""'),
198 ('... 456"""','... 456"""'),
198 ],
199 ],
199 [('....__class__','....__class__'),
200 [('....__class__','....__class__'),
200 ],
201 ],
201 [('a=5', 'a=5'),
202 [('a=5', 'a=5'),
202 ('...', ''),
203 ('...', ''),
203 ],
204 ],
204 [('>>> def f(x):', 'def f(x):'),
205 [('>>> def f(x):', 'def f(x):'),
205 ('...', ''),
206 ('...', ''),
206 ('... return x', ' return x'),
207 ('... return x', ' return x'),
207 ],
208 ],
208 [('board = """....', 'board = """....'),
209 [('board = """....', 'board = """....'),
209 ('....', '....'),
210 ('....', '....'),
210 ('...."""', '...."""'),
211 ('...."""', '...."""'),
211 ],
212 ],
212 ],
213 ],
213
214
214 ipy_prompt =
215 ipy_prompt =
215 [ [('In [24]: for i in range(10):','for i in range(10):'),
216 [ [('In [24]: for i in range(10):','for i in range(10):'),
216 (' ....: print i',' print i'),
217 (' ....: print i',' print i'),
217 (' ....: ', ''),
218 (' ....: ', ''),
218 ],
219 ],
219 [('In [24]: for i in range(10):','for i in range(10):'),
220 [('In [24]: for i in range(10):','for i in range(10):'),
220 # Qt console prompts expand with spaces, not dots
221 # Qt console prompts expand with spaces, not dots
221 (' ...: print i',' print i'),
222 (' ...: print i',' print i'),
222 (' ...: ', ''),
223 (' ...: ', ''),
223 ],
224 ],
224 [('In [24]: for i in range(10):','for i in range(10):'),
225 [('In [24]: for i in range(10):','for i in range(10):'),
225 # Sometimes whitespace preceding '...' has been removed
226 # Sometimes whitespace preceding '...' has been removed
226 ('...: print i',' print i'),
227 ('...: print i',' print i'),
227 ('...: ', ''),
228 ('...: ', ''),
228 ],
229 ],
229 [('In [24]: for i in range(10):','for i in range(10):'),
230 [('In [24]: for i in range(10):','for i in range(10):'),
230 # Space after last continuation prompt has been removed (issue #6674)
231 # Space after last continuation prompt has been removed (issue #6674)
231 ('...: print i',' print i'),
232 ('...: print i',' print i'),
232 ('...:', ''),
233 ('...:', ''),
233 ],
234 ],
234 [('In [2]: a="""','a="""'),
235 [('In [2]: a="""','a="""'),
235 (' ...: 123"""','123"""'),
236 (' ...: 123"""','123"""'),
236 ],
237 ],
237 [('a="""','a="""'),
238 [('a="""','a="""'),
238 (' ...: 123','123'),
239 (' ...: 123','123'),
239 (' ...: 456"""','456"""'),
240 (' ...: 456"""','456"""'),
240 ],
241 ],
241 [('a="""','a="""'),
242 [('a="""','a="""'),
242 ('In [1]: 123','123'),
243 ('In [1]: 123','123'),
243 (' ...: 456"""','456"""'),
244 (' ...: 456"""','456"""'),
244 ],
245 ],
245 [('a="""','a="""'),
246 [('a="""','a="""'),
246 ('123','123'),
247 ('123','123'),
247 (' ...: 456"""',' ...: 456"""'),
248 (' ...: 456"""',' ...: 456"""'),
248 ],
249 ],
249 ],
250 ],
250
251
251 multiline_datastructure_prompt =
252 multiline_datastructure_prompt =
252 [ [('>>> a = [1,','a = [1,'),
253 [ [('>>> a = [1,','a = [1,'),
253 ('... 2]','2]'),
254 ('... 2]','2]'),
254 ],
255 ],
255 ],
256 ],
256
257
257 multiline_datastructure =
258 multiline_datastructure =
258 [ [('b = ("%s"', None),
259 [ [('b = ("%s"', None),
259 ('# comment', None),
260 ('# comment', None),
260 ('%foo )', 'b = ("%s"\n# comment\n%foo )'),
261 ('%foo )', 'b = ("%s"\n# comment\n%foo )'),
261 ],
262 ],
262 ],
263 ],
263
264
264 multiline_string =
265 multiline_string =
265 [ [("'''foo?", None),
266 [ [("'''foo?", None),
266 ("bar'''", "'''foo?\nbar'''"),
267 ("bar'''", "'''foo?\nbar'''"),
267 ],
268 ],
268 ],
269 ],
269
270
270 leading_indent =
271 leading_indent =
271 [ [(' print "hi"','print "hi"'),
272 [ [(' print "hi"','print "hi"'),
272 ],
273 ],
273 [(' for a in range(5):','for a in range(5):'),
274 [(' for a in range(5):','for a in range(5):'),
274 (' a*2',' a*2'),
275 (' a*2',' a*2'),
275 ],
276 ],
276 [(' a="""','a="""'),
277 [(' a="""','a="""'),
277 (' 123"""','123"""'),
278 (' 123"""','123"""'),
278 ],
279 ],
279 [('a="""','a="""'),
280 [('a="""','a="""'),
280 (' 123"""',' 123"""'),
281 (' 123"""',' 123"""'),
281 ],
282 ],
282 ],
283 ],
283
284
284 cellmagic =
285 cellmagic =
285 [ [(u'%%foo a', None),
286 [ [(u'%%foo a', None),
286 (None, u_fmt("get_ipython().run_cell_magic('foo', 'a', '')")),
287 (None, u_fmt("get_ipython().run_cell_magic('foo', 'a', '')")),
287 ],
288 ],
288 [(u'%%bar 123', None),
289 [(u'%%bar 123', None),
289 (u'hello', None),
290 (u'hello', None),
290 (None , u_fmt("get_ipython().run_cell_magic('bar', '123', 'hello')")),
291 (None , u_fmt("get_ipython().run_cell_magic('bar', '123', 'hello')")),
291 ],
292 ],
292 [(u'a=5', 'a=5'),
293 [(u'a=5', 'a=5'),
293 (u'%%cellmagic', '%%cellmagic'),
294 (u'%%cellmagic', '%%cellmagic'),
294 ],
295 ],
295 ],
296 ],
296
297
297 escaped =
298 escaped =
298 [ [('%abc def \\', None),
299 [ [('%abc def \\', None),
299 ('ghi', u_fmt("get_ipython().run_line_magic('abc', 'def ghi')")),
300 ('ghi', u_fmt("get_ipython().run_line_magic('abc', 'def ghi')")),
300 ],
301 ],
301 [('%abc def \\', None),
302 [('%abc def \\', None),
302 ('ghi\\', None),
303 ('ghi\\', None),
303 (None, u_fmt("get_ipython().run_line_magic('abc', 'def ghi')")),
304 (None, u_fmt("get_ipython().run_line_magic('abc', 'def ghi')")),
304 ],
305 ],
305 ],
306 ],
306
307
307 assign_magic =
308 assign_magic =
308 [ [(u'a = %bc de \\', None),
309 [ [(u'a = %bc de \\', None),
309 (u'fg', u_fmt("a = get_ipython().run_line_magic('bc', 'de fg')")),
310 (u'fg', u_fmt("a = get_ipython().run_line_magic('bc', 'de fg')")),
310 ],
311 ],
311 [(u'a = %bc de \\', None),
312 [(u'a = %bc de \\', None),
312 (u'fg\\', None),
313 (u'fg\\', None),
313 (None, u_fmt("a = get_ipython().run_line_magic('bc', 'de fg')")),
314 (None, u_fmt("a = get_ipython().run_line_magic('bc', 'de fg')")),
314 ],
315 ],
315 ],
316 ],
316
317
317 assign_system =
318 assign_system =
318 [ [(u'a = !bc de \\', None),
319 [ [(u'a = !bc de \\', None),
319 (u'fg', u_fmt("a = get_ipython().getoutput('bc de fg')")),
320 (u'fg', u_fmt("a = get_ipython().getoutput('bc de fg')")),
320 ],
321 ],
321 [(u'a = !bc de \\', None),
322 [(u'a = !bc de \\', None),
322 (u'fg\\', None),
323 (u'fg\\', None),
323 (None, u_fmt("a = get_ipython().getoutput('bc de fg')")),
324 (None, u_fmt("a = get_ipython().getoutput('bc de fg')")),
324 ],
325 ],
325 ],
326 ],
326 )
327 )
327
328
328
329
329 def test_assign_system():
330 def test_assign_system():
330 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
331 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
331
332
332 def test_assign_magic():
333 def test_assign_magic():
333 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
334 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
334
335
335 def test_classic_prompt():
336 def test_classic_prompt():
336 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
337 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
337 for example in syntax_ml['classic_prompt']:
338 for example in syntax_ml['classic_prompt']:
338 transform_checker(example, ipt.classic_prompt)
339 transform_checker(example, ipt.classic_prompt)
339 for example in syntax_ml['multiline_datastructure_prompt']:
340 for example in syntax_ml['multiline_datastructure_prompt']:
340 transform_checker(example, ipt.classic_prompt)
341 transform_checker(example, ipt.classic_prompt)
341
342
342 # Check that we don't transform the second line if the first is obviously
343 # Check that we don't transform the second line if the first is obviously
343 # IPython syntax
344 # IPython syntax
344 transform_checker([
345 transform_checker([
345 (u'%foo', '%foo'),
346 (u'%foo', '%foo'),
346 (u'>>> bar', '>>> bar'),
347 (u'>>> bar', '>>> bar'),
347 ], ipt.classic_prompt)
348 ], ipt.classic_prompt)
348
349
349
350
350 def test_ipy_prompt():
351 def test_ipy_prompt():
351 tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
352 tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
352 for example in syntax_ml['ipy_prompt']:
353 for example in syntax_ml['ipy_prompt']:
353 transform_checker(example, ipt.ipy_prompt)
354 transform_checker(example, ipt.ipy_prompt)
354
355
355 # Check that we don't transform the second line if we're inside a cell magic
356 # Check that we don't transform the second line if we're inside a cell magic
356 transform_checker([
357 transform_checker([
357 (u'%%foo', '%%foo'),
358 (u'%%foo', '%%foo'),
358 (u'In [1]: bar', 'In [1]: bar'),
359 (u'In [1]: bar', 'In [1]: bar'),
359 ], ipt.ipy_prompt)
360 ], ipt.ipy_prompt)
360
361
361 def test_assemble_logical_lines():
362 def test_assemble_logical_lines():
362 tests = \
363 tests = \
363 [ [(u"a = \\", None),
364 [ [(u"a = \\", None),
364 (u"123", u"a = 123"),
365 (u"123", u"a = 123"),
365 ],
366 ],
366 [(u"a = \\", None), # Test resetting when within a multi-line string
367 [(u"a = \\", None), # Test resetting when within a multi-line string
367 (u"12 *\\", None),
368 (u"12 *\\", None),
368 (None, u"a = 12 *"),
369 (None, u"a = 12 *"),
369 ],
370 ],
370 [(u"# foo\\", u"# foo\\"), # Comments can't be continued like this
371 [(u"# foo\\", u"# foo\\"), # Comments can't be continued like this
371 ],
372 ],
372 ]
373 ]
373 for example in tests:
374 for example in tests:
374 transform_checker(example, ipt.assemble_logical_lines)
375 transform_checker(example, ipt.assemble_logical_lines)
375
376
376 def test_assemble_python_lines():
377 def test_assemble_python_lines():
377 tests = \
378 tests = \
378 [ [(u"a = '''", None),
379 [ [(u"a = '''", None),
379 (u"abc'''", u"a = '''\nabc'''"),
380 (u"abc'''", u"a = '''\nabc'''"),
380 ],
381 ],
381 [(u"a = '''", None), # Test resetting when within a multi-line string
382 [(u"a = '''", None), # Test resetting when within a multi-line string
382 (u"def", None),
383 (u"def", None),
383 (None, u"a = '''\ndef"),
384 (None, u"a = '''\ndef"),
384 ],
385 ],
385 [(u"a = [1,", None),
386 [(u"a = [1,", None),
386 (u"2]", u"a = [1,\n2]"),
387 (u"2]", u"a = [1,\n2]"),
387 ],
388 ],
388 [(u"a = [1,", None), # Test resetting when within a multi-line string
389 [(u"a = [1,", None), # Test resetting when within a multi-line string
389 (u"2,", None),
390 (u"2,", None),
390 (None, u"a = [1,\n2,"),
391 (None, u"a = [1,\n2,"),
391 ],
392 ],
392 [(u"a = '''", None), # Test line continuation within a multi-line string
393 [(u"a = '''", None), # Test line continuation within a multi-line string
393 (u"abc\\", None),
394 (u"abc\\", None),
394 (u"def", None),
395 (u"def", None),
395 (u"'''", u"a = '''\nabc\\\ndef\n'''"),
396 (u"'''", u"a = '''\nabc\\\ndef\n'''"),
396 ],
397 ],
397 ] + syntax_ml['multiline_datastructure']
398 ] + syntax_ml['multiline_datastructure']
398 for example in tests:
399 for example in tests:
399 transform_checker(example, ipt.assemble_python_lines)
400 transform_checker(example, ipt.assemble_python_lines)
400
401
401
402
402 def test_help_end():
403 def test_help_end():
403 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
404 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
404
405
405 def test_escaped_noesc():
406 def test_escaped_noesc():
406 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_noesc'])
407 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_noesc'])
407
408
408
409
409 def test_escaped_shell():
410 def test_escaped_shell():
410 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_shell'])
411 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_shell'])
411
412
412
413
413 def test_escaped_help():
414 def test_escaped_help():
414 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_help'])
415 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_help'])
415
416
416
417
417 def test_escaped_magic():
418 def test_escaped_magic():
418 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_magic'])
419 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_magic'])
419
420
420
421
421 def test_escaped_quote():
422 def test_escaped_quote():
422 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote'])
423 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote'])
423
424
424
425
425 def test_escaped_quote2():
426 def test_escaped_quote2():
426 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote2'])
427 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote2'])
427
428
428
429
429 def test_escaped_paren():
430 def test_escaped_paren():
430 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_paren'])
431 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_paren'])
431
432
432
433
433 def test_cellmagic():
434 def test_cellmagic():
434 for example in syntax_ml['cellmagic']:
435 for example in syntax_ml['cellmagic']:
435 transform_checker(example, ipt.cellmagic)
436 transform_checker(example, ipt.cellmagic)
436
437
437 line_example = [(u'%%bar 123', None),
438 line_example = [(u'%%bar 123', None),
438 (u'hello', None),
439 (u'hello', None),
439 (u'' , u_fmt("get_ipython().run_cell_magic('bar', '123', 'hello')")),
440 (u'' , u_fmt("get_ipython().run_cell_magic('bar', '123', 'hello')")),
440 ]
441 ]
441 transform_checker(line_example, ipt.cellmagic, end_on_blank_line=True)
442 transform_checker(line_example, ipt.cellmagic, end_on_blank_line=True)
442
443
443 def test_has_comment():
444 def test_has_comment():
444 tests = [('text', False),
445 tests = [('text', False),
445 ('text #comment', True),
446 ('text #comment', True),
446 ('text #comment\n', True),
447 ('text #comment\n', True),
447 ('#comment', True),
448 ('#comment', True),
448 ('#comment\n', True),
449 ('#comment\n', True),
449 ('a = "#string"', False),
450 ('a = "#string"', False),
450 ('a = "#string" # comment', True),
451 ('a = "#string" # comment', True),
451 ('a #comment not "string"', True),
452 ('a #comment not "string"', True),
452 ]
453 ]
453 tt.check_pairs(ipt.has_comment, tests)
454 tt.check_pairs(ipt.has_comment, tests)
454
455
455 @ipt.TokenInputTransformer.wrap
456 @ipt.TokenInputTransformer.wrap
456 def decistmt(tokens):
457 def decistmt(tokens):
457 """Substitute Decimals for floats in a string of statements.
458 """Substitute Decimals for floats in a string of statements.
458
459
459 Based on an example from the tokenize module docs.
460 Based on an example from the tokenize module docs.
460 """
461 """
461 result = []
462 result = []
462 for toknum, tokval, _, _, _ in tokens:
463 for toknum, tokval, _, _, _ in tokens:
463 if toknum == tokenize.NUMBER and '.' in tokval: # replace NUMBER tokens
464 if toknum == tokenize.NUMBER and '.' in tokval: # replace NUMBER tokens
464 for newtok in [
465 for newtok in [
465 (tokenize.NAME, 'Decimal'),
466 (tokenize.NAME, 'Decimal'),
466 (tokenize.OP, '('),
467 (tokenize.OP, '('),
467 (tokenize.STRING, repr(tokval)),
468 (tokenize.STRING, repr(tokval)),
468 (tokenize.OP, ')')
469 (tokenize.OP, ')')
469 ]:
470 ]:
470 yield newtok
471 yield newtok
471 else:
472 else:
472 yield (toknum, tokval)
473 yield (toknum, tokval)
473
474
474
475
475
476
476 def test_token_input_transformer():
477 def test_token_input_transformer():
477 tests = [(u'1.2', u_fmt(u"Decimal ('1.2')")),
478 tests = [(u'1.2', u_fmt(u"Decimal ('1.2')")),
478 (u'"1.2"', u'"1.2"'),
479 (u'"1.2"', u'"1.2"'),
479 ]
480 ]
480 tt.check_pairs(transform_and_reset(decistmt), tests)
481 tt.check_pairs(transform_and_reset(decistmt), tests)
481 ml_tests = \
482 ml_tests = \
482 [ [(u"a = 1.2; b = '''x", None),
483 [ [(u"a = 1.2; b = '''x", None),
483 (u"y'''", u_fmt(u"a =Decimal ('1.2');b ='''x\ny'''")),
484 (u"y'''", u_fmt(u"a =Decimal ('1.2');b ='''x\ny'''")),
484 ],
485 ],
485 [(u"a = [1.2,", None),
486 [(u"a = [1.2,", None),
486 (u"3]", u_fmt(u"a =[Decimal ('1.2'),\n3 ]")),
487 (u"3]", u_fmt(u"a =[Decimal ('1.2'),\n3 ]")),
487 ],
488 ],
488 [(u"a = '''foo", None), # Test resetting when within a multi-line string
489 [(u"a = '''foo", None), # Test resetting when within a multi-line string
489 (u"bar", None),
490 (u"bar", None),
490 (None, u"a = '''foo\nbar"),
491 (None, u"a = '''foo\nbar"),
491 ],
492 ],
492 ]
493 ]
493 for example in ml_tests:
494 for example in ml_tests:
494 transform_checker(example, decistmt)
495 transform_checker(example, decistmt)
@@ -1,284 +1,292 b''
1 """Tests for the token-based transformers in IPython.core.inputtransformer2
1 """Tests for the token-based transformers in IPython.core.inputtransformer2
2
2
3 Line-based transformers are the simpler ones; token-based transformers are
3 Line-based transformers are the simpler ones; token-based transformers are
4 more complex. See test_inputtransformer2_line for tests for line-based
4 more complex. See test_inputtransformer2_line for tests for line-based
5 transformations.
5 transformations.
6 """
6 """
7 import nose.tools as nt
7 import nose.tools as nt
8 import string
8 import string
9
9
10 from IPython.core import inputtransformer2 as ipt2
10 from IPython.core import inputtransformer2 as ipt2
11 from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op
11 from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op
12
12
13 from textwrap import dedent
13 from textwrap import dedent
14
14
15 MULTILINE_MAGIC = ("""\
15 MULTILINE_MAGIC = ("""\
16 a = f()
16 a = f()
17 %foo \\
17 %foo \\
18 bar
18 bar
19 g()
19 g()
20 """.splitlines(keepends=True), (2, 0), """\
20 """.splitlines(keepends=True), (2, 0), """\
21 a = f()
21 a = f()
22 get_ipython().run_line_magic('foo', ' bar')
22 get_ipython().run_line_magic('foo', ' bar')
23 g()
23 g()
24 """.splitlines(keepends=True))
24 """.splitlines(keepends=True))
25
25
26 INDENTED_MAGIC = ("""\
26 INDENTED_MAGIC = ("""\
27 for a in range(5):
27 for a in range(5):
28 %ls
28 %ls
29 """.splitlines(keepends=True), (2, 4), """\
29 """.splitlines(keepends=True), (2, 4), """\
30 for a in range(5):
30 for a in range(5):
31 get_ipython().run_line_magic('ls', '')
31 get_ipython().run_line_magic('ls', '')
32 """.splitlines(keepends=True))
32 """.splitlines(keepends=True))
33
33
34 MULTILINE_MAGIC_ASSIGN = ("""\
34 MULTILINE_MAGIC_ASSIGN = ("""\
35 a = f()
35 a = f()
36 b = %foo \\
36 b = %foo \\
37 bar
37 bar
38 g()
38 g()
39 """.splitlines(keepends=True), (2, 4), """\
39 """.splitlines(keepends=True), (2, 4), """\
40 a = f()
40 a = f()
41 b = get_ipython().run_line_magic('foo', ' bar')
41 b = get_ipython().run_line_magic('foo', ' bar')
42 g()
42 g()
43 """.splitlines(keepends=True))
43 """.splitlines(keepends=True))
44
44
45 MULTILINE_SYSTEM_ASSIGN = ("""\
45 MULTILINE_SYSTEM_ASSIGN = ("""\
46 a = f()
46 a = f()
47 b = !foo \\
47 b = !foo \\
48 bar
48 bar
49 g()
49 g()
50 """.splitlines(keepends=True), (2, 4), """\
50 """.splitlines(keepends=True), (2, 4), """\
51 a = f()
51 a = f()
52 b = get_ipython().getoutput('foo bar')
52 b = get_ipython().getoutput('foo bar')
53 g()
53 g()
54 """.splitlines(keepends=True))
54 """.splitlines(keepends=True))
55
55
56 #####
56 #####
57
57
58 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
58 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
59 def test():
59 def test():
60 for i in range(1):
60 for i in range(1):
61 print(i)
61 print(i)
62 res =! ls
62 res =! ls
63 """.splitlines(keepends=True), (4, 7), '''\
63 """.splitlines(keepends=True), (4, 7), '''\
64 def test():
64 def test():
65 for i in range(1):
65 for i in range(1):
66 print(i)
66 print(i)
67 res =get_ipython().getoutput(\' ls\')
67 res =get_ipython().getoutput(\' ls\')
68 '''.splitlines(keepends=True))
68 '''.splitlines(keepends=True))
69
69
70 ######
70 ######
71
71
72 AUTOCALL_QUOTE = (
72 AUTOCALL_QUOTE = (
73 [",f 1 2 3\n"], (1, 0),
73 [",f 1 2 3\n"], (1, 0),
74 ['f("1", "2", "3")\n']
74 ['f("1", "2", "3")\n']
75 )
75 )
76
76
77 AUTOCALL_QUOTE2 = (
77 AUTOCALL_QUOTE2 = (
78 [";f 1 2 3\n"], (1, 0),
78 [";f 1 2 3\n"], (1, 0),
79 ['f("1 2 3")\n']
79 ['f("1 2 3")\n']
80 )
80 )
81
81
82 AUTOCALL_PAREN = (
82 AUTOCALL_PAREN = (
83 ["/f 1 2 3\n"], (1, 0),
83 ["/f 1 2 3\n"], (1, 0),
84 ['f(1, 2, 3)\n']
84 ['f(1, 2, 3)\n']
85 )
85 )
86
86
87 SIMPLE_HELP = (
87 SIMPLE_HELP = (
88 ["foo?\n"], (1, 0),
88 ["foo?\n"], (1, 0),
89 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
89 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
90 )
90 )
91
91
92 DETAILED_HELP = (
92 DETAILED_HELP = (
93 ["foo??\n"], (1, 0),
93 ["foo??\n"], (1, 0),
94 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
94 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
95 )
95 )
96
96
97 MAGIC_HELP = (
97 MAGIC_HELP = (
98 ["%foo?\n"], (1, 0),
98 ["%foo?\n"], (1, 0),
99 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
99 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
100 )
100 )
101
101
102 HELP_IN_EXPR = (
102 HELP_IN_EXPR = (
103 ["a = b + c?\n"], (1, 0),
103 ["a = b + c?\n"], (1, 0),
104 ["get_ipython().set_next_input('a = b + c');"
104 ["get_ipython().set_next_input('a = b + c');"
105 "get_ipython().run_line_magic('pinfo', 'c')\n"]
105 "get_ipython().run_line_magic('pinfo', 'c')\n"]
106 )
106 )
107
107
108 HELP_CONTINUED_LINE = ("""\
108 HELP_CONTINUED_LINE = ("""\
109 a = \\
109 a = \\
110 zip?
110 zip?
111 """.splitlines(keepends=True), (1, 0),
111 """.splitlines(keepends=True), (1, 0),
112 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
112 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
113 )
113 )
114
114
115 HELP_MULTILINE = ("""\
115 HELP_MULTILINE = ("""\
116 (a,
116 (a,
117 b) = zip?
117 b) = zip?
118 """.splitlines(keepends=True), (1, 0),
118 """.splitlines(keepends=True), (1, 0),
119 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
119 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
120 )
120 )
121
121
122 HELP_UNICODE = (
123 ["π.foo?\n"], (1, 0),
124 ["get_ipython().run_line_magic('pinfo', 'π.foo')\n"]
125 )
126
122
127
123 def null_cleanup_transformer(lines):
128 def null_cleanup_transformer(lines):
124 """
129 """
125 A cleanup transform that returns an empty list.
130 A cleanup transform that returns an empty list.
126 """
131 """
127 return []
132 return []
128
133
129 def check_make_token_by_line_never_ends_empty():
134 def check_make_token_by_line_never_ends_empty():
130 """
135 """
131 Check that not sequence of single or double characters ends up leading to en empty list of tokens
136 Check that not sequence of single or double characters ends up leading to en empty list of tokens
132 """
137 """
133 from string import printable
138 from string import printable
134 for c in printable:
139 for c in printable:
135 nt.assert_not_equal(make_tokens_by_line(c)[-1], [])
140 nt.assert_not_equal(make_tokens_by_line(c)[-1], [])
136 for k in printable:
141 for k in printable:
137 nt.assert_not_equal(make_tokens_by_line(c+k)[-1], [])
142 nt.assert_not_equal(make_tokens_by_line(c+k)[-1], [])
138
143
139 def check_find(transformer, case, match=True):
144 def check_find(transformer, case, match=True):
140 sample, expected_start, _ = case
145 sample, expected_start, _ = case
141 tbl = make_tokens_by_line(sample)
146 tbl = make_tokens_by_line(sample)
142 res = transformer.find(tbl)
147 res = transformer.find(tbl)
143 if match:
148 if match:
144 # start_line is stored 0-indexed, expected values are 1-indexed
149 # start_line is stored 0-indexed, expected values are 1-indexed
145 nt.assert_equal((res.start_line+1, res.start_col), expected_start)
150 nt.assert_equal((res.start_line+1, res.start_col), expected_start)
146 return res
151 return res
147 else:
152 else:
148 nt.assert_is(res, None)
153 nt.assert_is(res, None)
149
154
150 def check_transform(transformer_cls, case):
155 def check_transform(transformer_cls, case):
151 lines, start, expected = case
156 lines, start, expected = case
152 transformer = transformer_cls(start)
157 transformer = transformer_cls(start)
153 nt.assert_equal(transformer.transform(lines), expected)
158 nt.assert_equal(transformer.transform(lines), expected)
154
159
155 def test_continued_line():
160 def test_continued_line():
156 lines = MULTILINE_MAGIC_ASSIGN[0]
161 lines = MULTILINE_MAGIC_ASSIGN[0]
157 nt.assert_equal(ipt2.find_end_of_continued_line(lines, 1), 2)
162 nt.assert_equal(ipt2.find_end_of_continued_line(lines, 1), 2)
158
163
159 nt.assert_equal(ipt2.assemble_continued_line(lines, (1, 5), 2), "foo bar")
164 nt.assert_equal(ipt2.assemble_continued_line(lines, (1, 5), 2), "foo bar")
160
165
161 def test_find_assign_magic():
166 def test_find_assign_magic():
162 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
167 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
163 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
168 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
164 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
169 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
165
170
166 def test_transform_assign_magic():
171 def test_transform_assign_magic():
167 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
172 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
168
173
169 def test_find_assign_system():
174 def test_find_assign_system():
170 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
175 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
171 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
176 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
172 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
177 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
173 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
178 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
174 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
179 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
175
180
176 def test_transform_assign_system():
181 def test_transform_assign_system():
177 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
182 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
178 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
183 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
179
184
180 def test_find_magic_escape():
185 def test_find_magic_escape():
181 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
186 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
182 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
187 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
183 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
188 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
184
189
185 def test_transform_magic_escape():
190 def test_transform_magic_escape():
186 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
191 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
187 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
192 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
188
193
189 def test_find_autocalls():
194 def test_find_autocalls():
190 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
195 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
191 print("Testing %r" % case[0])
196 print("Testing %r" % case[0])
192 check_find(ipt2.EscapedCommand, case)
197 check_find(ipt2.EscapedCommand, case)
193
198
194 def test_transform_autocall():
199 def test_transform_autocall():
195 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
200 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
196 print("Testing %r" % case[0])
201 print("Testing %r" % case[0])
197 check_transform(ipt2.EscapedCommand, case)
202 check_transform(ipt2.EscapedCommand, case)
198
203
199 def test_find_help():
204 def test_find_help():
200 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
205 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
201 check_find(ipt2.HelpEnd, case)
206 check_find(ipt2.HelpEnd, case)
202
207
203 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
208 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
204 nt.assert_equal(tf.q_line, 1)
209 nt.assert_equal(tf.q_line, 1)
205 nt.assert_equal(tf.q_col, 3)
210 nt.assert_equal(tf.q_col, 3)
206
211
207 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
212 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
208 nt.assert_equal(tf.q_line, 1)
213 nt.assert_equal(tf.q_line, 1)
209 nt.assert_equal(tf.q_col, 8)
214 nt.assert_equal(tf.q_col, 8)
210
215
211 # ? in a comment does not trigger help
216 # ? in a comment does not trigger help
212 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
217 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
213 # Nor in a string
218 # Nor in a string
214 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
219 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
215
220
216 def test_transform_help():
221 def test_transform_help():
217 tf = ipt2.HelpEnd((1, 0), (1, 9))
222 tf = ipt2.HelpEnd((1, 0), (1, 9))
218 nt.assert_equal(tf.transform(HELP_IN_EXPR[0]), HELP_IN_EXPR[2])
223 nt.assert_equal(tf.transform(HELP_IN_EXPR[0]), HELP_IN_EXPR[2])
219
224
220 tf = ipt2.HelpEnd((1, 0), (2, 3))
225 tf = ipt2.HelpEnd((1, 0), (2, 3))
221 nt.assert_equal(tf.transform(HELP_CONTINUED_LINE[0]), HELP_CONTINUED_LINE[2])
226 nt.assert_equal(tf.transform(HELP_CONTINUED_LINE[0]), HELP_CONTINUED_LINE[2])
222
227
223 tf = ipt2.HelpEnd((1, 0), (2, 8))
228 tf = ipt2.HelpEnd((1, 0), (2, 8))
224 nt.assert_equal(tf.transform(HELP_MULTILINE[0]), HELP_MULTILINE[2])
229 nt.assert_equal(tf.transform(HELP_MULTILINE[0]), HELP_MULTILINE[2])
225
230
231 tf = ipt2.HelpEnd((1, 0), (1, 0))
232 nt.assert_equal(tf.transform(HELP_UNICODE[0]), HELP_UNICODE[2])
233
226 def test_find_assign_op_dedent():
234 def test_find_assign_op_dedent():
227 """
235 """
228 be careful that empty token like dedent are not counted as parens
236 be careful that empty token like dedent are not counted as parens
229 """
237 """
230 class Tk:
238 class Tk:
231 def __init__(self, s):
239 def __init__(self, s):
232 self.string = s
240 self.string = s
233
241
234 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','a','=','b')]), 2)
242 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','a','=','b')]), 2)
235 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','(', 'a','=','b', ')', '=' ,'5')]), 6)
243 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','(', 'a','=','b', ')', '=' ,'5')]), 6)
236
244
237 def test_check_complete():
245 def test_check_complete():
238 cc = ipt2.TransformerManager().check_complete
246 cc = ipt2.TransformerManager().check_complete
239 nt.assert_equal(cc("a = 1"), ('complete', None))
247 nt.assert_equal(cc("a = 1"), ('complete', None))
240 nt.assert_equal(cc("for a in range(5):"), ('incomplete', 4))
248 nt.assert_equal(cc("for a in range(5):"), ('incomplete', 4))
241 nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ('incomplete', 8))
249 nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ('incomplete', 8))
242 nt.assert_equal(cc("raise = 2"), ('invalid', None))
250 nt.assert_equal(cc("raise = 2"), ('invalid', None))
243 nt.assert_equal(cc("a = [1,\n2,"), ('incomplete', 0))
251 nt.assert_equal(cc("a = [1,\n2,"), ('incomplete', 0))
244 nt.assert_equal(cc(")"), ('incomplete', 0))
252 nt.assert_equal(cc(")"), ('incomplete', 0))
245 nt.assert_equal(cc("\\\r\n"), ('incomplete', 0))
253 nt.assert_equal(cc("\\\r\n"), ('incomplete', 0))
246 nt.assert_equal(cc("a = '''\n hi"), ('incomplete', 3))
254 nt.assert_equal(cc("a = '''\n hi"), ('incomplete', 3))
247 nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None))
255 nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None))
248 nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash
256 nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash
249 nt.assert_equal(cc("1\\\n+2"), ('complete', None))
257 nt.assert_equal(cc("1\\\n+2"), ('complete', None))
250 nt.assert_equal(cc("exit"), ('complete', None))
258 nt.assert_equal(cc("exit"), ('complete', None))
251
259
252 example = dedent("""
260 example = dedent("""
253 if True:
261 if True:
254 a=1""" )
262 a=1""" )
255
263
256 nt.assert_equal(cc(example), ('incomplete', 4))
264 nt.assert_equal(cc(example), ('incomplete', 4))
257 nt.assert_equal(cc(example+'\n'), ('complete', None))
265 nt.assert_equal(cc(example+'\n'), ('complete', None))
258 nt.assert_equal(cc(example+'\n '), ('complete', None))
266 nt.assert_equal(cc(example+'\n '), ('complete', None))
259
267
260 # no need to loop on all the letters/numbers.
268 # no need to loop on all the letters/numbers.
261 short = '12abAB'+string.printable[62:]
269 short = '12abAB'+string.printable[62:]
262 for c in short:
270 for c in short:
263 # test does not raise:
271 # test does not raise:
264 cc(c)
272 cc(c)
265 for k in short:
273 for k in short:
266 cc(c+k)
274 cc(c+k)
267
275
268 nt.assert_equal(cc("def f():\n x=0\n \\\n "), ('incomplete', 2))
276 nt.assert_equal(cc("def f():\n x=0\n \\\n "), ('incomplete', 2))
269
277
270 def test_check_complete_II():
278 def test_check_complete_II():
271 """
279 """
272 Test that multiple line strings are properly handled.
280 Test that multiple line strings are properly handled.
273
281
274 Separate test function for convenience
282 Separate test function for convenience
275
283
276 """
284 """
277 cc = ipt2.TransformerManager().check_complete
285 cc = ipt2.TransformerManager().check_complete
278 nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4))
286 nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4))
279
287
280
288
281 def test_null_cleanup_transformer():
289 def test_null_cleanup_transformer():
282 manager = ipt2.TransformerManager()
290 manager = ipt2.TransformerManager()
283 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
291 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
284 nt.assert_is(manager.transform_cell(""), "")
292 nt.assert_is(manager.transform_cell(""), "")
@@ -1,1246 +1,1248 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6
6
7 import io
7 import io
8 import os
8 import os
9 import re
9 import re
10 import sys
10 import sys
11 import warnings
11 import warnings
12 from textwrap import dedent
12 from textwrap import dedent
13 from unittest import TestCase
13 from unittest import TestCase
14 from unittest import mock
14 from unittest import mock
15 from importlib import invalidate_caches
15 from importlib import invalidate_caches
16 from io import StringIO
16 from io import StringIO
17
17
18 import nose.tools as nt
18 import nose.tools as nt
19
19
20 import shlex
20 import shlex
21
21
22 from IPython import get_ipython
22 from IPython import get_ipython
23 from IPython.core import magic
23 from IPython.core import magic
24 from IPython.core.error import UsageError
24 from IPython.core.error import UsageError
25 from IPython.core.magic import (Magics, magics_class, line_magic,
25 from IPython.core.magic import (Magics, magics_class, line_magic,
26 cell_magic,
26 cell_magic,
27 register_line_magic, register_cell_magic)
27 register_line_magic, register_cell_magic)
28 from IPython.core.magics import execution, script, code, logging, osm
28 from IPython.core.magics import execution, script, code, logging, osm
29 from IPython.testing import decorators as dec
29 from IPython.testing import decorators as dec
30 from IPython.testing import tools as tt
30 from IPython.testing import tools as tt
31 from IPython.utils.io import capture_output
31 from IPython.utils.io import capture_output
32 from IPython.utils.tempdir import (TemporaryDirectory,
32 from IPython.utils.tempdir import (TemporaryDirectory,
33 TemporaryWorkingDirectory)
33 TemporaryWorkingDirectory)
34 from IPython.utils.process import find_cmd
34 from IPython.utils.process import find_cmd
35
35
36
36
37 @magic.magics_class
37 @magic.magics_class
38 class DummyMagics(magic.Magics): pass
38 class DummyMagics(magic.Magics): pass
39
39
40 def test_extract_code_ranges():
40 def test_extract_code_ranges():
41 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
41 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
42 expected = [(0, 1),
42 expected = [(0, 1),
43 (2, 3),
43 (2, 3),
44 (4, 6),
44 (4, 6),
45 (6, 9),
45 (6, 9),
46 (9, 14),
46 (9, 14),
47 (16, None),
47 (16, None),
48 (None, 9),
48 (None, 9),
49 (9, None),
49 (9, None),
50 (None, 13),
50 (None, 13),
51 (None, None)]
51 (None, None)]
52 actual = list(code.extract_code_ranges(instr))
52 actual = list(code.extract_code_ranges(instr))
53 nt.assert_equal(actual, expected)
53 nt.assert_equal(actual, expected)
54
54
55 def test_extract_symbols():
55 def test_extract_symbols():
56 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
56 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
57 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
57 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
58 expected = [([], ['a']),
58 expected = [([], ['a']),
59 (["def b():\n return 42\n"], []),
59 (["def b():\n return 42\n"], []),
60 (["class A: pass\n"], []),
60 (["class A: pass\n"], []),
61 (["class A: pass\n", "def b():\n return 42\n"], []),
61 (["class A: pass\n", "def b():\n return 42\n"], []),
62 (["class A: pass\n"], ['a']),
62 (["class A: pass\n"], ['a']),
63 ([], ['z'])]
63 ([], ['z'])]
64 for symbols, exp in zip(symbols_args, expected):
64 for symbols, exp in zip(symbols_args, expected):
65 nt.assert_equal(code.extract_symbols(source, symbols), exp)
65 nt.assert_equal(code.extract_symbols(source, symbols), exp)
66
66
67
67
68 def test_extract_symbols_raises_exception_with_non_python_code():
68 def test_extract_symbols_raises_exception_with_non_python_code():
69 source = ("=begin A Ruby program :)=end\n"
69 source = ("=begin A Ruby program :)=end\n"
70 "def hello\n"
70 "def hello\n"
71 "puts 'Hello world'\n"
71 "puts 'Hello world'\n"
72 "end")
72 "end")
73 with nt.assert_raises(SyntaxError):
73 with nt.assert_raises(SyntaxError):
74 code.extract_symbols(source, "hello")
74 code.extract_symbols(source, "hello")
75
75
76
76
77 def test_magic_not_found():
77 def test_magic_not_found():
78 # magic not found raises UsageError
78 # magic not found raises UsageError
79 with nt.assert_raises(UsageError):
79 with nt.assert_raises(UsageError):
80 _ip.magic('doesntexist')
80 _ip.magic('doesntexist')
81
81
82 # ensure result isn't success when a magic isn't found
82 # ensure result isn't success when a magic isn't found
83 result = _ip.run_cell('%doesntexist')
83 result = _ip.run_cell('%doesntexist')
84 assert isinstance(result.error_in_exec, UsageError)
84 assert isinstance(result.error_in_exec, UsageError)
85
85
86
86
87 def test_cell_magic_not_found():
87 def test_cell_magic_not_found():
88 # magic not found raises UsageError
88 # magic not found raises UsageError
89 with nt.assert_raises(UsageError):
89 with nt.assert_raises(UsageError):
90 _ip.run_cell_magic('doesntexist', 'line', 'cell')
90 _ip.run_cell_magic('doesntexist', 'line', 'cell')
91
91
92 # ensure result isn't success when a magic isn't found
92 # ensure result isn't success when a magic isn't found
93 result = _ip.run_cell('%%doesntexist')
93 result = _ip.run_cell('%%doesntexist')
94 assert isinstance(result.error_in_exec, UsageError)
94 assert isinstance(result.error_in_exec, UsageError)
95
95
96
96
97 def test_magic_error_status():
97 def test_magic_error_status():
98 def fail(shell):
98 def fail(shell):
99 1/0
99 1/0
100 _ip.register_magic_function(fail)
100 _ip.register_magic_function(fail)
101 result = _ip.run_cell('%fail')
101 result = _ip.run_cell('%fail')
102 assert isinstance(result.error_in_exec, ZeroDivisionError)
102 assert isinstance(result.error_in_exec, ZeroDivisionError)
103
103
104
104
105 def test_config():
105 def test_config():
106 """ test that config magic does not raise
106 """ test that config magic does not raise
107 can happen if Configurable init is moved too early into
107 can happen if Configurable init is moved too early into
108 Magics.__init__ as then a Config object will be registered as a
108 Magics.__init__ as then a Config object will be registered as a
109 magic.
109 magic.
110 """
110 """
111 ## should not raise.
111 ## should not raise.
112 _ip.magic('config')
112 _ip.magic('config')
113
113
114 def test_config_available_configs():
114 def test_config_available_configs():
115 """ test that config magic prints available configs in unique and
115 """ test that config magic prints available configs in unique and
116 sorted order. """
116 sorted order. """
117 with capture_output() as captured:
117 with capture_output() as captured:
118 _ip.magic('config')
118 _ip.magic('config')
119
119
120 stdout = captured.stdout
120 stdout = captured.stdout
121 config_classes = stdout.strip().split('\n')[1:]
121 config_classes = stdout.strip().split('\n')[1:]
122 nt.assert_list_equal(config_classes, sorted(set(config_classes)))
122 nt.assert_list_equal(config_classes, sorted(set(config_classes)))
123
123
124 def test_config_print_class():
124 def test_config_print_class():
125 """ test that config with a classname prints the class's options. """
125 """ test that config with a classname prints the class's options. """
126 with capture_output() as captured:
126 with capture_output() as captured:
127 _ip.magic('config TerminalInteractiveShell')
127 _ip.magic('config TerminalInteractiveShell')
128
128
129 stdout = captured.stdout
129 stdout = captured.stdout
130 if not re.match("TerminalInteractiveShell.* options", stdout.splitlines()[0]):
130 if not re.match("TerminalInteractiveShell.* options", stdout.splitlines()[0]):
131 print(stdout)
131 print(stdout)
132 raise AssertionError("1st line of stdout not like "
132 raise AssertionError("1st line of stdout not like "
133 "'TerminalInteractiveShell.* options'")
133 "'TerminalInteractiveShell.* options'")
134
134
135 def test_rehashx():
135 def test_rehashx():
136 # clear up everything
136 # clear up everything
137 _ip.alias_manager.clear_aliases()
137 _ip.alias_manager.clear_aliases()
138 del _ip.db['syscmdlist']
138 del _ip.db['syscmdlist']
139
139
140 _ip.magic('rehashx')
140 _ip.magic('rehashx')
141 # Practically ALL ipython development systems will have more than 10 aliases
141 # Practically ALL ipython development systems will have more than 10 aliases
142
142
143 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
143 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
144 for name, cmd in _ip.alias_manager.aliases:
144 for name, cmd in _ip.alias_manager.aliases:
145 # we must strip dots from alias names
145 # we must strip dots from alias names
146 nt.assert_not_in('.', name)
146 nt.assert_not_in('.', name)
147
147
148 # rehashx must fill up syscmdlist
148 # rehashx must fill up syscmdlist
149 scoms = _ip.db['syscmdlist']
149 scoms = _ip.db['syscmdlist']
150 nt.assert_true(len(scoms) > 10)
150 nt.assert_true(len(scoms) > 10)
151
151
152
152
153
153
154 def test_magic_parse_options():
154 def test_magic_parse_options():
155 """Test that we don't mangle paths when parsing magic options."""
155 """Test that we don't mangle paths when parsing magic options."""
156 ip = get_ipython()
156 ip = get_ipython()
157 path = 'c:\\x'
157 path = 'c:\\x'
158 m = DummyMagics(ip)
158 m = DummyMagics(ip)
159 opts = m.parse_options('-f %s' % path,'f:')[0]
159 opts = m.parse_options('-f %s' % path,'f:')[0]
160 # argv splitting is os-dependent
160 # argv splitting is os-dependent
161 if os.name == 'posix':
161 if os.name == 'posix':
162 expected = 'c:x'
162 expected = 'c:x'
163 else:
163 else:
164 expected = path
164 expected = path
165 nt.assert_equal(opts['f'], expected)
165 nt.assert_equal(opts['f'], expected)
166
166
167 def test_magic_parse_long_options():
167 def test_magic_parse_long_options():
168 """Magic.parse_options can handle --foo=bar long options"""
168 """Magic.parse_options can handle --foo=bar long options"""
169 ip = get_ipython()
169 ip = get_ipython()
170 m = DummyMagics(ip)
170 m = DummyMagics(ip)
171 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
171 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
172 nt.assert_in('foo', opts)
172 nt.assert_in('foo', opts)
173 nt.assert_in('bar', opts)
173 nt.assert_in('bar', opts)
174 nt.assert_equal(opts['bar'], "bubble")
174 nt.assert_equal(opts['bar'], "bubble")
175
175
176
176
177 def doctest_hist_f():
177 def doctest_hist_f():
178 """Test %hist -f with temporary filename.
178 """Test %hist -f with temporary filename.
179
179
180 In [9]: import tempfile
180 In [9]: import tempfile
181
181
182 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
182 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
183
183
184 In [11]: %hist -nl -f $tfile 3
184 In [11]: %hist -nl -f $tfile 3
185
185
186 In [13]: import os; os.unlink(tfile)
186 In [13]: import os; os.unlink(tfile)
187 """
187 """
188
188
189
189
190 def doctest_hist_op():
190 def doctest_hist_op():
191 """Test %hist -op
191 """Test %hist -op
192
192
193 In [1]: class b(float):
193 In [1]: class b(float):
194 ...: pass
194 ...: pass
195 ...:
195 ...:
196
196
197 In [2]: class s(object):
197 In [2]: class s(object):
198 ...: def __str__(self):
198 ...: def __str__(self):
199 ...: return 's'
199 ...: return 's'
200 ...:
200 ...:
201
201
202 In [3]:
202 In [3]:
203
203
204 In [4]: class r(b):
204 In [4]: class r(b):
205 ...: def __repr__(self):
205 ...: def __repr__(self):
206 ...: return 'r'
206 ...: return 'r'
207 ...:
207 ...:
208
208
209 In [5]: class sr(s,r): pass
209 In [5]: class sr(s,r): pass
210 ...:
210 ...:
211
211
212 In [6]:
212 In [6]:
213
213
214 In [7]: bb=b()
214 In [7]: bb=b()
215
215
216 In [8]: ss=s()
216 In [8]: ss=s()
217
217
218 In [9]: rr=r()
218 In [9]: rr=r()
219
219
220 In [10]: ssrr=sr()
220 In [10]: ssrr=sr()
221
221
222 In [11]: 4.5
222 In [11]: 4.5
223 Out[11]: 4.5
223 Out[11]: 4.5
224
224
225 In [12]: str(ss)
225 In [12]: str(ss)
226 Out[12]: 's'
226 Out[12]: 's'
227
227
228 In [13]:
228 In [13]:
229
229
230 In [14]: %hist -op
230 In [14]: %hist -op
231 >>> class b:
231 >>> class b:
232 ... pass
232 ... pass
233 ...
233 ...
234 >>> class s(b):
234 >>> class s(b):
235 ... def __str__(self):
235 ... def __str__(self):
236 ... return 's'
236 ... return 's'
237 ...
237 ...
238 >>>
238 >>>
239 >>> class r(b):
239 >>> class r(b):
240 ... def __repr__(self):
240 ... def __repr__(self):
241 ... return 'r'
241 ... return 'r'
242 ...
242 ...
243 >>> class sr(s,r): pass
243 >>> class sr(s,r): pass
244 >>>
244 >>>
245 >>> bb=b()
245 >>> bb=b()
246 >>> ss=s()
246 >>> ss=s()
247 >>> rr=r()
247 >>> rr=r()
248 >>> ssrr=sr()
248 >>> ssrr=sr()
249 >>> 4.5
249 >>> 4.5
250 4.5
250 4.5
251 >>> str(ss)
251 >>> str(ss)
252 's'
252 's'
253 >>>
253 >>>
254 """
254 """
255
255
256 def test_hist_pof():
256 def test_hist_pof():
257 ip = get_ipython()
257 ip = get_ipython()
258 ip.run_cell(u"1+2", store_history=True)
258 ip.run_cell(u"1+2", store_history=True)
259 #raise Exception(ip.history_manager.session_number)
259 #raise Exception(ip.history_manager.session_number)
260 #raise Exception(list(ip.history_manager._get_range_session()))
260 #raise Exception(list(ip.history_manager._get_range_session()))
261 with TemporaryDirectory() as td:
261 with TemporaryDirectory() as td:
262 tf = os.path.join(td, 'hist.py')
262 tf = os.path.join(td, 'hist.py')
263 ip.run_line_magic('history', '-pof %s' % tf)
263 ip.run_line_magic('history', '-pof %s' % tf)
264 assert os.path.isfile(tf)
264 assert os.path.isfile(tf)
265
265
266
266
267 def test_macro():
267 def test_macro():
268 ip = get_ipython()
268 ip = get_ipython()
269 ip.history_manager.reset() # Clear any existing history.
269 ip.history_manager.reset() # Clear any existing history.
270 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
270 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
271 for i, cmd in enumerate(cmds, start=1):
271 for i, cmd in enumerate(cmds, start=1):
272 ip.history_manager.store_inputs(i, cmd)
272 ip.history_manager.store_inputs(i, cmd)
273 ip.magic("macro test 1-3")
273 ip.magic("macro test 1-3")
274 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
274 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
275
275
276 # List macros
276 # List macros
277 nt.assert_in("test", ip.magic("macro"))
277 nt.assert_in("test", ip.magic("macro"))
278
278
279
279
280 def test_macro_run():
280 def test_macro_run():
281 """Test that we can run a multi-line macro successfully."""
281 """Test that we can run a multi-line macro successfully."""
282 ip = get_ipython()
282 ip = get_ipython()
283 ip.history_manager.reset()
283 ip.history_manager.reset()
284 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
284 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
285 for cmd in cmds:
285 for cmd in cmds:
286 ip.run_cell(cmd, store_history=True)
286 ip.run_cell(cmd, store_history=True)
287 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint(a)\n")
287 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint(a)\n")
288 with tt.AssertPrints("12"):
288 with tt.AssertPrints("12"):
289 ip.run_cell("test")
289 ip.run_cell("test")
290 with tt.AssertPrints("13"):
290 with tt.AssertPrints("13"):
291 ip.run_cell("test")
291 ip.run_cell("test")
292
292
293
293
294 def test_magic_magic():
294 def test_magic_magic():
295 """Test %magic"""
295 """Test %magic"""
296 ip = get_ipython()
296 ip = get_ipython()
297 with capture_output() as captured:
297 with capture_output() as captured:
298 ip.magic("magic")
298 ip.magic("magic")
299
299
300 stdout = captured.stdout
300 stdout = captured.stdout
301 nt.assert_in('%magic', stdout)
301 nt.assert_in('%magic', stdout)
302 nt.assert_in('IPython', stdout)
302 nt.assert_in('IPython', stdout)
303 nt.assert_in('Available', stdout)
303 nt.assert_in('Available', stdout)
304
304
305
305
306 @dec.skipif_not_numpy
306 @dec.skipif_not_numpy
307 def test_numpy_reset_array_undec():
307 def test_numpy_reset_array_undec():
308 "Test '%reset array' functionality"
308 "Test '%reset array' functionality"
309 _ip.ex('import numpy as np')
309 _ip.ex('import numpy as np')
310 _ip.ex('a = np.empty(2)')
310 _ip.ex('a = np.empty(2)')
311 nt.assert_in('a', _ip.user_ns)
311 nt.assert_in('a', _ip.user_ns)
312 _ip.magic('reset -f array')
312 _ip.magic('reset -f array')
313 nt.assert_not_in('a', _ip.user_ns)
313 nt.assert_not_in('a', _ip.user_ns)
314
314
315 def test_reset_out():
315 def test_reset_out():
316 "Test '%reset out' magic"
316 "Test '%reset out' magic"
317 _ip.run_cell("parrot = 'dead'", store_history=True)
317 _ip.run_cell("parrot = 'dead'", store_history=True)
318 # test '%reset -f out', make an Out prompt
318 # test '%reset -f out', make an Out prompt
319 _ip.run_cell("parrot", store_history=True)
319 _ip.run_cell("parrot", store_history=True)
320 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
320 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
321 _ip.magic('reset -f out')
321 _ip.magic('reset -f out')
322 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
322 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
323 nt.assert_equal(len(_ip.user_ns['Out']), 0)
323 nt.assert_equal(len(_ip.user_ns['Out']), 0)
324
324
325 def test_reset_in():
325 def test_reset_in():
326 "Test '%reset in' magic"
326 "Test '%reset in' magic"
327 # test '%reset -f in'
327 # test '%reset -f in'
328 _ip.run_cell("parrot", store_history=True)
328 _ip.run_cell("parrot", store_history=True)
329 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
329 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
330 _ip.magic('%reset -f in')
330 _ip.magic('%reset -f in')
331 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
331 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
332 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
332 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
333
333
334 def test_reset_dhist():
334 def test_reset_dhist():
335 "Test '%reset dhist' magic"
335 "Test '%reset dhist' magic"
336 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
336 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
337 _ip.magic('cd ' + os.path.dirname(nt.__file__))
337 _ip.magic('cd ' + os.path.dirname(nt.__file__))
338 _ip.magic('cd -')
338 _ip.magic('cd -')
339 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
339 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
340 _ip.magic('reset -f dhist')
340 _ip.magic('reset -f dhist')
341 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
341 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
342 _ip.run_cell("_dh = [d for d in tmp]") #restore
342 _ip.run_cell("_dh = [d for d in tmp]") #restore
343
343
344 def test_reset_in_length():
344 def test_reset_in_length():
345 "Test that '%reset in' preserves In[] length"
345 "Test that '%reset in' preserves In[] length"
346 _ip.run_cell("print 'foo'")
346 _ip.run_cell("print 'foo'")
347 _ip.run_cell("reset -f in")
347 _ip.run_cell("reset -f in")
348 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
348 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
349
349
350 class TestResetErrors(TestCase):
350 class TestResetErrors(TestCase):
351
351
352 def test_reset_redefine(self):
352 def test_reset_redefine(self):
353
353
354 @magics_class
354 @magics_class
355 class KernelMagics(Magics):
355 class KernelMagics(Magics):
356 @line_magic
356 @line_magic
357 def less(self, shell): pass
357 def less(self, shell): pass
358
358
359 _ip.register_magics(KernelMagics)
359 _ip.register_magics(KernelMagics)
360
360
361 with self.assertLogs() as cm:
361 with self.assertLogs() as cm:
362 # hack, we want to just capture logs, but assertLogs fails if not
362 # hack, we want to just capture logs, but assertLogs fails if not
363 # logs get produce.
363 # logs get produce.
364 # so log one things we ignore.
364 # so log one things we ignore.
365 import logging as log_mod
365 import logging as log_mod
366 log = log_mod.getLogger()
366 log = log_mod.getLogger()
367 log.info('Nothing')
367 log.info('Nothing')
368 # end hack.
368 # end hack.
369 _ip.run_cell("reset -f")
369 _ip.run_cell("reset -f")
370
370
371 assert len(cm.output) == 1
371 assert len(cm.output) == 1
372 for out in cm.output:
372 for out in cm.output:
373 assert "Invalid alias" not in out
373 assert "Invalid alias" not in out
374
374
375 def test_tb_syntaxerror():
375 def test_tb_syntaxerror():
376 """test %tb after a SyntaxError"""
376 """test %tb after a SyntaxError"""
377 ip = get_ipython()
377 ip = get_ipython()
378 ip.run_cell("for")
378 ip.run_cell("for")
379
379
380 # trap and validate stdout
380 # trap and validate stdout
381 save_stdout = sys.stdout
381 save_stdout = sys.stdout
382 try:
382 try:
383 sys.stdout = StringIO()
383 sys.stdout = StringIO()
384 ip.run_cell("%tb")
384 ip.run_cell("%tb")
385 out = sys.stdout.getvalue()
385 out = sys.stdout.getvalue()
386 finally:
386 finally:
387 sys.stdout = save_stdout
387 sys.stdout = save_stdout
388 # trim output, and only check the last line
388 # trim output, and only check the last line
389 last_line = out.rstrip().splitlines()[-1].strip()
389 last_line = out.rstrip().splitlines()[-1].strip()
390 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
390 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
391
391
392
392
393 def test_time():
393 def test_time():
394 ip = get_ipython()
394 ip = get_ipython()
395
395
396 with tt.AssertPrints("Wall time: "):
396 with tt.AssertPrints("Wall time: "):
397 ip.run_cell("%time None")
397 ip.run_cell("%time None")
398
398
399 ip.run_cell("def f(kmjy):\n"
399 ip.run_cell("def f(kmjy):\n"
400 " %time print (2*kmjy)")
400 " %time print (2*kmjy)")
401
401
402 with tt.AssertPrints("Wall time: "):
402 with tt.AssertPrints("Wall time: "):
403 with tt.AssertPrints("hihi", suppress=False):
403 with tt.AssertPrints("hihi", suppress=False):
404 ip.run_cell("f('hi')")
404 ip.run_cell("f('hi')")
405
405
406 def test_time_last_not_expression():
406 def test_time_last_not_expression():
407 ip.run_cell("%%time\n"
407 ip.run_cell("%%time\n"
408 "var_1 = 1\n"
408 "var_1 = 1\n"
409 "var_2 = 2\n")
409 "var_2 = 2\n")
410 assert ip.user_ns['var_1'] == 1
410 assert ip.user_ns['var_1'] == 1
411 del ip.user_ns['var_1']
411 del ip.user_ns['var_1']
412 assert ip.user_ns['var_2'] == 2
412 assert ip.user_ns['var_2'] == 2
413 del ip.user_ns['var_2']
413 del ip.user_ns['var_2']
414
414
415
415
416 @dec.skip_win32
416 @dec.skip_win32
417 def test_time2():
417 def test_time2():
418 ip = get_ipython()
418 ip = get_ipython()
419
419
420 with tt.AssertPrints("CPU times: user "):
420 with tt.AssertPrints("CPU times: user "):
421 ip.run_cell("%time None")
421 ip.run_cell("%time None")
422
422
423 def test_time3():
423 def test_time3():
424 """Erroneous magic function calls, issue gh-3334"""
424 """Erroneous magic function calls, issue gh-3334"""
425 ip = get_ipython()
425 ip = get_ipython()
426 ip.user_ns.pop('run', None)
426 ip.user_ns.pop('run', None)
427
427
428 with tt.AssertNotPrints("not found", channel='stderr'):
428 with tt.AssertNotPrints("not found", channel='stderr'):
429 ip.run_cell("%%time\n"
429 ip.run_cell("%%time\n"
430 "run = 0\n"
430 "run = 0\n"
431 "run += 1")
431 "run += 1")
432
432
433 def test_multiline_time():
433 def test_multiline_time():
434 """Make sure last statement from time return a value."""
434 """Make sure last statement from time return a value."""
435 ip = get_ipython()
435 ip = get_ipython()
436 ip.user_ns.pop('run', None)
436 ip.user_ns.pop('run', None)
437
437
438 ip.run_cell(dedent("""\
438 ip.run_cell(dedent("""\
439 %%time
439 %%time
440 a = "ho"
440 a = "ho"
441 b = "hey"
441 b = "hey"
442 a+b
442 a+b
443 """))
443 """))
444 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
444 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
445
445
446 def test_time_local_ns():
446 def test_time_local_ns():
447 """
447 """
448 Test that local_ns is actually global_ns when running a cell magic
448 Test that local_ns is actually global_ns when running a cell magic
449 """
449 """
450 ip = get_ipython()
450 ip = get_ipython()
451 ip.run_cell("%%time\n"
451 ip.run_cell("%%time\n"
452 "myvar = 1")
452 "myvar = 1")
453 nt.assert_equal(ip.user_ns['myvar'], 1)
453 nt.assert_equal(ip.user_ns['myvar'], 1)
454 del ip.user_ns['myvar']
454 del ip.user_ns['myvar']
455
455
456 def test_doctest_mode():
456 def test_doctest_mode():
457 "Toggle doctest_mode twice, it should be a no-op and run without error"
457 "Toggle doctest_mode twice, it should be a no-op and run without error"
458 _ip.magic('doctest_mode')
458 _ip.magic('doctest_mode')
459 _ip.magic('doctest_mode')
459 _ip.magic('doctest_mode')
460
460
461
461
462 def test_parse_options():
462 def test_parse_options():
463 """Tests for basic options parsing in magics."""
463 """Tests for basic options parsing in magics."""
464 # These are only the most minimal of tests, more should be added later. At
464 # These are only the most minimal of tests, more should be added later. At
465 # the very least we check that basic text/unicode calls work OK.
465 # the very least we check that basic text/unicode calls work OK.
466 m = DummyMagics(_ip)
466 m = DummyMagics(_ip)
467 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
467 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
468 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
468 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
469
469
470
470
471 def test_dirops():
471 def test_dirops():
472 """Test various directory handling operations."""
472 """Test various directory handling operations."""
473 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
473 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
474 curpath = os.getcwd
474 curpath = os.getcwd
475 startdir = os.getcwd()
475 startdir = os.getcwd()
476 ipdir = os.path.realpath(_ip.ipython_dir)
476 ipdir = os.path.realpath(_ip.ipython_dir)
477 try:
477 try:
478 _ip.magic('cd "%s"' % ipdir)
478 _ip.magic('cd "%s"' % ipdir)
479 nt.assert_equal(curpath(), ipdir)
479 nt.assert_equal(curpath(), ipdir)
480 _ip.magic('cd -')
480 _ip.magic('cd -')
481 nt.assert_equal(curpath(), startdir)
481 nt.assert_equal(curpath(), startdir)
482 _ip.magic('pushd "%s"' % ipdir)
482 _ip.magic('pushd "%s"' % ipdir)
483 nt.assert_equal(curpath(), ipdir)
483 nt.assert_equal(curpath(), ipdir)
484 _ip.magic('popd')
484 _ip.magic('popd')
485 nt.assert_equal(curpath(), startdir)
485 nt.assert_equal(curpath(), startdir)
486 finally:
486 finally:
487 os.chdir(startdir)
487 os.chdir(startdir)
488
488
489
489
490 def test_cd_force_quiet():
490 def test_cd_force_quiet():
491 """Test OSMagics.cd_force_quiet option"""
491 """Test OSMagics.cd_force_quiet option"""
492 _ip.config.OSMagics.cd_force_quiet = True
492 _ip.config.OSMagics.cd_force_quiet = True
493 osmagics = osm.OSMagics(shell=_ip)
493 osmagics = osm.OSMagics(shell=_ip)
494
494
495 startdir = os.getcwd()
495 startdir = os.getcwd()
496 ipdir = os.path.realpath(_ip.ipython_dir)
496 ipdir = os.path.realpath(_ip.ipython_dir)
497
497
498 try:
498 try:
499 with tt.AssertNotPrints(ipdir):
499 with tt.AssertNotPrints(ipdir):
500 osmagics.cd('"%s"' % ipdir)
500 osmagics.cd('"%s"' % ipdir)
501 with tt.AssertNotPrints(startdir):
501 with tt.AssertNotPrints(startdir):
502 osmagics.cd('-')
502 osmagics.cd('-')
503 finally:
503 finally:
504 os.chdir(startdir)
504 os.chdir(startdir)
505
505
506
506
507 def test_xmode():
507 def test_xmode():
508 # Calling xmode three times should be a no-op
508 # Calling xmode three times should be a no-op
509 xmode = _ip.InteractiveTB.mode
509 xmode = _ip.InteractiveTB.mode
510 for i in range(4):
510 for i in range(4):
511 _ip.magic("xmode")
511 _ip.magic("xmode")
512 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
512 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
513
513
514 def test_reset_hard():
514 def test_reset_hard():
515 monitor = []
515 monitor = []
516 class A(object):
516 class A(object):
517 def __del__(self):
517 def __del__(self):
518 monitor.append(1)
518 monitor.append(1)
519 def __repr__(self):
519 def __repr__(self):
520 return "<A instance>"
520 return "<A instance>"
521
521
522 _ip.user_ns["a"] = A()
522 _ip.user_ns["a"] = A()
523 _ip.run_cell("a")
523 _ip.run_cell("a")
524
524
525 nt.assert_equal(monitor, [])
525 nt.assert_equal(monitor, [])
526 _ip.magic("reset -f")
526 _ip.magic("reset -f")
527 nt.assert_equal(monitor, [1])
527 nt.assert_equal(monitor, [1])
528
528
529 class TestXdel(tt.TempFileMixin):
529 class TestXdel(tt.TempFileMixin):
530 def test_xdel(self):
530 def test_xdel(self):
531 """Test that references from %run are cleared by xdel."""
531 """Test that references from %run are cleared by xdel."""
532 src = ("class A(object):\n"
532 src = ("class A(object):\n"
533 " monitor = []\n"
533 " monitor = []\n"
534 " def __del__(self):\n"
534 " def __del__(self):\n"
535 " self.monitor.append(1)\n"
535 " self.monitor.append(1)\n"
536 "a = A()\n")
536 "a = A()\n")
537 self.mktmp(src)
537 self.mktmp(src)
538 # %run creates some hidden references...
538 # %run creates some hidden references...
539 _ip.magic("run %s" % self.fname)
539 _ip.magic("run %s" % self.fname)
540 # ... as does the displayhook.
540 # ... as does the displayhook.
541 _ip.run_cell("a")
541 _ip.run_cell("a")
542
542
543 monitor = _ip.user_ns["A"].monitor
543 monitor = _ip.user_ns["A"].monitor
544 nt.assert_equal(monitor, [])
544 nt.assert_equal(monitor, [])
545
545
546 _ip.magic("xdel a")
546 _ip.magic("xdel a")
547
547
548 # Check that a's __del__ method has been called.
548 # Check that a's __del__ method has been called.
549 nt.assert_equal(monitor, [1])
549 nt.assert_equal(monitor, [1])
550
550
551 def doctest_who():
551 def doctest_who():
552 """doctest for %who
552 """doctest for %who
553
553
554 In [1]: %reset -f
554 In [1]: %reset -f
555
555
556 In [2]: alpha = 123
556 In [2]: alpha = 123
557
557
558 In [3]: beta = 'beta'
558 In [3]: beta = 'beta'
559
559
560 In [4]: %who int
560 In [4]: %who int
561 alpha
561 alpha
562
562
563 In [5]: %who str
563 In [5]: %who str
564 beta
564 beta
565
565
566 In [6]: %whos
566 In [6]: %whos
567 Variable Type Data/Info
567 Variable Type Data/Info
568 ----------------------------
568 ----------------------------
569 alpha int 123
569 alpha int 123
570 beta str beta
570 beta str beta
571
571
572 In [7]: %who_ls
572 In [7]: %who_ls
573 Out[7]: ['alpha', 'beta']
573 Out[7]: ['alpha', 'beta']
574 """
574 """
575
575
576 def test_whos():
576 def test_whos():
577 """Check that whos is protected against objects where repr() fails."""
577 """Check that whos is protected against objects where repr() fails."""
578 class A(object):
578 class A(object):
579 def __repr__(self):
579 def __repr__(self):
580 raise Exception()
580 raise Exception()
581 _ip.user_ns['a'] = A()
581 _ip.user_ns['a'] = A()
582 _ip.magic("whos")
582 _ip.magic("whos")
583
583
584 def doctest_precision():
584 def doctest_precision():
585 """doctest for %precision
585 """doctest for %precision
586
586
587 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
587 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
588
588
589 In [2]: %precision 5
589 In [2]: %precision 5
590 Out[2]: '%.5f'
590 Out[2]: '%.5f'
591
591
592 In [3]: f.float_format
592 In [3]: f.float_format
593 Out[3]: '%.5f'
593 Out[3]: '%.5f'
594
594
595 In [4]: %precision %e
595 In [4]: %precision %e
596 Out[4]: '%e'
596 Out[4]: '%e'
597
597
598 In [5]: f(3.1415927)
598 In [5]: f(3.1415927)
599 Out[5]: '3.141593e+00'
599 Out[5]: '3.141593e+00'
600 """
600 """
601
601
602 def test_psearch():
602 def test_psearch():
603 with tt.AssertPrints("dict.fromkeys"):
603 with tt.AssertPrints("dict.fromkeys"):
604 _ip.run_cell("dict.fr*?")
604 _ip.run_cell("dict.fr*?")
605 with tt.AssertPrints("π.is_integer"):
606 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
605
607
606 def test_timeit_shlex():
608 def test_timeit_shlex():
607 """test shlex issues with timeit (#1109)"""
609 """test shlex issues with timeit (#1109)"""
608 _ip.ex("def f(*a,**kw): pass")
610 _ip.ex("def f(*a,**kw): pass")
609 _ip.magic('timeit -n1 "this is a bug".count(" ")')
611 _ip.magic('timeit -n1 "this is a bug".count(" ")')
610 _ip.magic('timeit -r1 -n1 f(" ", 1)')
612 _ip.magic('timeit -r1 -n1 f(" ", 1)')
611 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
613 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
612 _ip.magic('timeit -r1 -n1 ("a " + "b")')
614 _ip.magic('timeit -r1 -n1 ("a " + "b")')
613 _ip.magic('timeit -r1 -n1 f("a " + "b")')
615 _ip.magic('timeit -r1 -n1 f("a " + "b")')
614 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
616 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
615
617
616
618
617 def test_timeit_special_syntax():
619 def test_timeit_special_syntax():
618 "Test %%timeit with IPython special syntax"
620 "Test %%timeit with IPython special syntax"
619 @register_line_magic
621 @register_line_magic
620 def lmagic(line):
622 def lmagic(line):
621 ip = get_ipython()
623 ip = get_ipython()
622 ip.user_ns['lmagic_out'] = line
624 ip.user_ns['lmagic_out'] = line
623
625
624 # line mode test
626 # line mode test
625 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
627 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
626 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
628 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
627 # cell mode test
629 # cell mode test
628 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
630 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
629 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
631 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
630
632
631 def test_timeit_return():
633 def test_timeit_return():
632 """
634 """
633 test whether timeit -o return object
635 test whether timeit -o return object
634 """
636 """
635
637
636 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
638 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
637 assert(res is not None)
639 assert(res is not None)
638
640
639 def test_timeit_quiet():
641 def test_timeit_quiet():
640 """
642 """
641 test quiet option of timeit magic
643 test quiet option of timeit magic
642 """
644 """
643 with tt.AssertNotPrints("loops"):
645 with tt.AssertNotPrints("loops"):
644 _ip.run_cell("%timeit -n1 -r1 -q 1")
646 _ip.run_cell("%timeit -n1 -r1 -q 1")
645
647
646 def test_timeit_return_quiet():
648 def test_timeit_return_quiet():
647 with tt.AssertNotPrints("loops"):
649 with tt.AssertNotPrints("loops"):
648 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
650 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
649 assert (res is not None)
651 assert (res is not None)
650
652
651 def test_timeit_invalid_return():
653 def test_timeit_invalid_return():
652 with nt.assert_raises_regex(SyntaxError, "outside function"):
654 with nt.assert_raises_regex(SyntaxError, "outside function"):
653 _ip.run_line_magic('timeit', 'return')
655 _ip.run_line_magic('timeit', 'return')
654
656
655 @dec.skipif(execution.profile is None)
657 @dec.skipif(execution.profile is None)
656 def test_prun_special_syntax():
658 def test_prun_special_syntax():
657 "Test %%prun with IPython special syntax"
659 "Test %%prun with IPython special syntax"
658 @register_line_magic
660 @register_line_magic
659 def lmagic(line):
661 def lmagic(line):
660 ip = get_ipython()
662 ip = get_ipython()
661 ip.user_ns['lmagic_out'] = line
663 ip.user_ns['lmagic_out'] = line
662
664
663 # line mode test
665 # line mode test
664 _ip.run_line_magic('prun', '-q %lmagic my line')
666 _ip.run_line_magic('prun', '-q %lmagic my line')
665 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
667 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
666 # cell mode test
668 # cell mode test
667 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
669 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
668 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
670 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
669
671
670 @dec.skipif(execution.profile is None)
672 @dec.skipif(execution.profile is None)
671 def test_prun_quotes():
673 def test_prun_quotes():
672 "Test that prun does not clobber string escapes (GH #1302)"
674 "Test that prun does not clobber string escapes (GH #1302)"
673 _ip.magic(r"prun -q x = '\t'")
675 _ip.magic(r"prun -q x = '\t'")
674 nt.assert_equal(_ip.user_ns['x'], '\t')
676 nt.assert_equal(_ip.user_ns['x'], '\t')
675
677
676 def test_extension():
678 def test_extension():
677 # Debugging information for failures of this test
679 # Debugging information for failures of this test
678 print('sys.path:')
680 print('sys.path:')
679 for p in sys.path:
681 for p in sys.path:
680 print(' ', p)
682 print(' ', p)
681 print('CWD', os.getcwd())
683 print('CWD', os.getcwd())
682
684
683 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
685 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
684 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
686 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
685 sys.path.insert(0, daft_path)
687 sys.path.insert(0, daft_path)
686 try:
688 try:
687 _ip.user_ns.pop('arq', None)
689 _ip.user_ns.pop('arq', None)
688 invalidate_caches() # Clear import caches
690 invalidate_caches() # Clear import caches
689 _ip.magic("load_ext daft_extension")
691 _ip.magic("load_ext daft_extension")
690 nt.assert_equal(_ip.user_ns['arq'], 185)
692 nt.assert_equal(_ip.user_ns['arq'], 185)
691 _ip.magic("unload_ext daft_extension")
693 _ip.magic("unload_ext daft_extension")
692 assert 'arq' not in _ip.user_ns
694 assert 'arq' not in _ip.user_ns
693 finally:
695 finally:
694 sys.path.remove(daft_path)
696 sys.path.remove(daft_path)
695
697
696
698
697 def test_notebook_export_json():
699 def test_notebook_export_json():
698 _ip = get_ipython()
700 _ip = get_ipython()
699 _ip.history_manager.reset() # Clear any existing history.
701 _ip.history_manager.reset() # Clear any existing history.
700 cmds = [u"a=1", u"def b():\n return a**2", u"print('noël, été', b())"]
702 cmds = [u"a=1", u"def b():\n return a**2", u"print('noël, été', b())"]
701 for i, cmd in enumerate(cmds, start=1):
703 for i, cmd in enumerate(cmds, start=1):
702 _ip.history_manager.store_inputs(i, cmd)
704 _ip.history_manager.store_inputs(i, cmd)
703 with TemporaryDirectory() as td:
705 with TemporaryDirectory() as td:
704 outfile = os.path.join(td, "nb.ipynb")
706 outfile = os.path.join(td, "nb.ipynb")
705 _ip.magic("notebook -e %s" % outfile)
707 _ip.magic("notebook -e %s" % outfile)
706
708
707
709
708 class TestEnv(TestCase):
710 class TestEnv(TestCase):
709
711
710 def test_env(self):
712 def test_env(self):
711 env = _ip.magic("env")
713 env = _ip.magic("env")
712 self.assertTrue(isinstance(env, dict))
714 self.assertTrue(isinstance(env, dict))
713
715
714 def test_env_secret(self):
716 def test_env_secret(self):
715 env = _ip.magic("env")
717 env = _ip.magic("env")
716 hidden = "<hidden>"
718 hidden = "<hidden>"
717 with mock.patch.dict(
719 with mock.patch.dict(
718 os.environ,
720 os.environ,
719 {
721 {
720 "API_KEY": "abc123",
722 "API_KEY": "abc123",
721 "SECRET_THING": "ssshhh",
723 "SECRET_THING": "ssshhh",
722 "JUPYTER_TOKEN": "",
724 "JUPYTER_TOKEN": "",
723 "VAR": "abc"
725 "VAR": "abc"
724 }
726 }
725 ):
727 ):
726 env = _ip.magic("env")
728 env = _ip.magic("env")
727 assert env["API_KEY"] == hidden
729 assert env["API_KEY"] == hidden
728 assert env["SECRET_THING"] == hidden
730 assert env["SECRET_THING"] == hidden
729 assert env["JUPYTER_TOKEN"] == hidden
731 assert env["JUPYTER_TOKEN"] == hidden
730 assert env["VAR"] == "abc"
732 assert env["VAR"] == "abc"
731
733
732 def test_env_get_set_simple(self):
734 def test_env_get_set_simple(self):
733 env = _ip.magic("env var val1")
735 env = _ip.magic("env var val1")
734 self.assertEqual(env, None)
736 self.assertEqual(env, None)
735 self.assertEqual(os.environ['var'], 'val1')
737 self.assertEqual(os.environ['var'], 'val1')
736 self.assertEqual(_ip.magic("env var"), 'val1')
738 self.assertEqual(_ip.magic("env var"), 'val1')
737 env = _ip.magic("env var=val2")
739 env = _ip.magic("env var=val2")
738 self.assertEqual(env, None)
740 self.assertEqual(env, None)
739 self.assertEqual(os.environ['var'], 'val2')
741 self.assertEqual(os.environ['var'], 'val2')
740
742
741 def test_env_get_set_complex(self):
743 def test_env_get_set_complex(self):
742 env = _ip.magic("env var 'val1 '' 'val2")
744 env = _ip.magic("env var 'val1 '' 'val2")
743 self.assertEqual(env, None)
745 self.assertEqual(env, None)
744 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
746 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
745 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
747 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
746 env = _ip.magic('env var=val2 val3="val4')
748 env = _ip.magic('env var=val2 val3="val4')
747 self.assertEqual(env, None)
749 self.assertEqual(env, None)
748 self.assertEqual(os.environ['var'], 'val2 val3="val4')
750 self.assertEqual(os.environ['var'], 'val2 val3="val4')
749
751
750 def test_env_set_bad_input(self):
752 def test_env_set_bad_input(self):
751 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
753 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
752
754
753 def test_env_set_whitespace(self):
755 def test_env_set_whitespace(self):
754 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
756 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
755
757
756
758
757 class CellMagicTestCase(TestCase):
759 class CellMagicTestCase(TestCase):
758
760
759 def check_ident(self, magic):
761 def check_ident(self, magic):
760 # Manually called, we get the result
762 # Manually called, we get the result
761 out = _ip.run_cell_magic(magic, 'a', 'b')
763 out = _ip.run_cell_magic(magic, 'a', 'b')
762 nt.assert_equal(out, ('a','b'))
764 nt.assert_equal(out, ('a','b'))
763 # Via run_cell, it goes into the user's namespace via displayhook
765 # Via run_cell, it goes into the user's namespace via displayhook
764 _ip.run_cell('%%' + magic +' c\nd\n')
766 _ip.run_cell('%%' + magic +' c\nd\n')
765 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
767 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
766
768
767 def test_cell_magic_func_deco(self):
769 def test_cell_magic_func_deco(self):
768 "Cell magic using simple decorator"
770 "Cell magic using simple decorator"
769 @register_cell_magic
771 @register_cell_magic
770 def cellm(line, cell):
772 def cellm(line, cell):
771 return line, cell
773 return line, cell
772
774
773 self.check_ident('cellm')
775 self.check_ident('cellm')
774
776
775 def test_cell_magic_reg(self):
777 def test_cell_magic_reg(self):
776 "Cell magic manually registered"
778 "Cell magic manually registered"
777 def cellm(line, cell):
779 def cellm(line, cell):
778 return line, cell
780 return line, cell
779
781
780 _ip.register_magic_function(cellm, 'cell', 'cellm2')
782 _ip.register_magic_function(cellm, 'cell', 'cellm2')
781 self.check_ident('cellm2')
783 self.check_ident('cellm2')
782
784
783 def test_cell_magic_class(self):
785 def test_cell_magic_class(self):
784 "Cell magics declared via a class"
786 "Cell magics declared via a class"
785 @magics_class
787 @magics_class
786 class MyMagics(Magics):
788 class MyMagics(Magics):
787
789
788 @cell_magic
790 @cell_magic
789 def cellm3(self, line, cell):
791 def cellm3(self, line, cell):
790 return line, cell
792 return line, cell
791
793
792 _ip.register_magics(MyMagics)
794 _ip.register_magics(MyMagics)
793 self.check_ident('cellm3')
795 self.check_ident('cellm3')
794
796
795 def test_cell_magic_class2(self):
797 def test_cell_magic_class2(self):
796 "Cell magics declared via a class, #2"
798 "Cell magics declared via a class, #2"
797 @magics_class
799 @magics_class
798 class MyMagics2(Magics):
800 class MyMagics2(Magics):
799
801
800 @cell_magic('cellm4')
802 @cell_magic('cellm4')
801 def cellm33(self, line, cell):
803 def cellm33(self, line, cell):
802 return line, cell
804 return line, cell
803
805
804 _ip.register_magics(MyMagics2)
806 _ip.register_magics(MyMagics2)
805 self.check_ident('cellm4')
807 self.check_ident('cellm4')
806 # Check that nothing is registered as 'cellm33'
808 # Check that nothing is registered as 'cellm33'
807 c33 = _ip.find_cell_magic('cellm33')
809 c33 = _ip.find_cell_magic('cellm33')
808 nt.assert_equal(c33, None)
810 nt.assert_equal(c33, None)
809
811
810 def test_file():
812 def test_file():
811 """Basic %%writefile"""
813 """Basic %%writefile"""
812 ip = get_ipython()
814 ip = get_ipython()
813 with TemporaryDirectory() as td:
815 with TemporaryDirectory() as td:
814 fname = os.path.join(td, 'file1')
816 fname = os.path.join(td, 'file1')
815 ip.run_cell_magic("writefile", fname, u'\n'.join([
817 ip.run_cell_magic("writefile", fname, u'\n'.join([
816 'line1',
818 'line1',
817 'line2',
819 'line2',
818 ]))
820 ]))
819 with open(fname) as f:
821 with open(fname) as f:
820 s = f.read()
822 s = f.read()
821 nt.assert_in('line1\n', s)
823 nt.assert_in('line1\n', s)
822 nt.assert_in('line2', s)
824 nt.assert_in('line2', s)
823
825
824 @dec.skip_win32
826 @dec.skip_win32
825 def test_file_single_quote():
827 def test_file_single_quote():
826 """Basic %%writefile with embedded single quotes"""
828 """Basic %%writefile with embedded single quotes"""
827 ip = get_ipython()
829 ip = get_ipython()
828 with TemporaryDirectory() as td:
830 with TemporaryDirectory() as td:
829 fname = os.path.join(td, '\'file1\'')
831 fname = os.path.join(td, '\'file1\'')
830 ip.run_cell_magic("writefile", fname, u'\n'.join([
832 ip.run_cell_magic("writefile", fname, u'\n'.join([
831 'line1',
833 'line1',
832 'line2',
834 'line2',
833 ]))
835 ]))
834 with open(fname) as f:
836 with open(fname) as f:
835 s = f.read()
837 s = f.read()
836 nt.assert_in('line1\n', s)
838 nt.assert_in('line1\n', s)
837 nt.assert_in('line2', s)
839 nt.assert_in('line2', s)
838
840
839 @dec.skip_win32
841 @dec.skip_win32
840 def test_file_double_quote():
842 def test_file_double_quote():
841 """Basic %%writefile with embedded double quotes"""
843 """Basic %%writefile with embedded double quotes"""
842 ip = get_ipython()
844 ip = get_ipython()
843 with TemporaryDirectory() as td:
845 with TemporaryDirectory() as td:
844 fname = os.path.join(td, '"file1"')
846 fname = os.path.join(td, '"file1"')
845 ip.run_cell_magic("writefile", fname, u'\n'.join([
847 ip.run_cell_magic("writefile", fname, u'\n'.join([
846 'line1',
848 'line1',
847 'line2',
849 'line2',
848 ]))
850 ]))
849 with open(fname) as f:
851 with open(fname) as f:
850 s = f.read()
852 s = f.read()
851 nt.assert_in('line1\n', s)
853 nt.assert_in('line1\n', s)
852 nt.assert_in('line2', s)
854 nt.assert_in('line2', s)
853
855
854 def test_file_var_expand():
856 def test_file_var_expand():
855 """%%writefile $filename"""
857 """%%writefile $filename"""
856 ip = get_ipython()
858 ip = get_ipython()
857 with TemporaryDirectory() as td:
859 with TemporaryDirectory() as td:
858 fname = os.path.join(td, 'file1')
860 fname = os.path.join(td, 'file1')
859 ip.user_ns['filename'] = fname
861 ip.user_ns['filename'] = fname
860 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
862 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
861 'line1',
863 'line1',
862 'line2',
864 'line2',
863 ]))
865 ]))
864 with open(fname) as f:
866 with open(fname) as f:
865 s = f.read()
867 s = f.read()
866 nt.assert_in('line1\n', s)
868 nt.assert_in('line1\n', s)
867 nt.assert_in('line2', s)
869 nt.assert_in('line2', s)
868
870
869 def test_file_unicode():
871 def test_file_unicode():
870 """%%writefile with unicode cell"""
872 """%%writefile with unicode cell"""
871 ip = get_ipython()
873 ip = get_ipython()
872 with TemporaryDirectory() as td:
874 with TemporaryDirectory() as td:
873 fname = os.path.join(td, 'file1')
875 fname = os.path.join(td, 'file1')
874 ip.run_cell_magic("writefile", fname, u'\n'.join([
876 ip.run_cell_magic("writefile", fname, u'\n'.join([
875 u'liné1',
877 u'liné1',
876 u'liné2',
878 u'liné2',
877 ]))
879 ]))
878 with io.open(fname, encoding='utf-8') as f:
880 with io.open(fname, encoding='utf-8') as f:
879 s = f.read()
881 s = f.read()
880 nt.assert_in(u'liné1\n', s)
882 nt.assert_in(u'liné1\n', s)
881 nt.assert_in(u'liné2', s)
883 nt.assert_in(u'liné2', s)
882
884
883 def test_file_amend():
885 def test_file_amend():
884 """%%writefile -a amends files"""
886 """%%writefile -a amends files"""
885 ip = get_ipython()
887 ip = get_ipython()
886 with TemporaryDirectory() as td:
888 with TemporaryDirectory() as td:
887 fname = os.path.join(td, 'file2')
889 fname = os.path.join(td, 'file2')
888 ip.run_cell_magic("writefile", fname, u'\n'.join([
890 ip.run_cell_magic("writefile", fname, u'\n'.join([
889 'line1',
891 'line1',
890 'line2',
892 'line2',
891 ]))
893 ]))
892 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
894 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
893 'line3',
895 'line3',
894 'line4',
896 'line4',
895 ]))
897 ]))
896 with open(fname) as f:
898 with open(fname) as f:
897 s = f.read()
899 s = f.read()
898 nt.assert_in('line1\n', s)
900 nt.assert_in('line1\n', s)
899 nt.assert_in('line3\n', s)
901 nt.assert_in('line3\n', s)
900
902
901 def test_file_spaces():
903 def test_file_spaces():
902 """%%file with spaces in filename"""
904 """%%file with spaces in filename"""
903 ip = get_ipython()
905 ip = get_ipython()
904 with TemporaryWorkingDirectory() as td:
906 with TemporaryWorkingDirectory() as td:
905 fname = "file name"
907 fname = "file name"
906 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
908 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
907 'line1',
909 'line1',
908 'line2',
910 'line2',
909 ]))
911 ]))
910 with open(fname) as f:
912 with open(fname) as f:
911 s = f.read()
913 s = f.read()
912 nt.assert_in('line1\n', s)
914 nt.assert_in('line1\n', s)
913 nt.assert_in('line2', s)
915 nt.assert_in('line2', s)
914
916
915 def test_script_config():
917 def test_script_config():
916 ip = get_ipython()
918 ip = get_ipython()
917 ip.config.ScriptMagics.script_magics = ['whoda']
919 ip.config.ScriptMagics.script_magics = ['whoda']
918 sm = script.ScriptMagics(shell=ip)
920 sm = script.ScriptMagics(shell=ip)
919 nt.assert_in('whoda', sm.magics['cell'])
921 nt.assert_in('whoda', sm.magics['cell'])
920
922
921 @dec.skip_win32
923 @dec.skip_win32
922 def test_script_out():
924 def test_script_out():
923 ip = get_ipython()
925 ip = get_ipython()
924 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
926 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
925 nt.assert_equal(ip.user_ns['output'], 'hi\n')
927 nt.assert_equal(ip.user_ns['output'], 'hi\n')
926
928
927 @dec.skip_win32
929 @dec.skip_win32
928 def test_script_err():
930 def test_script_err():
929 ip = get_ipython()
931 ip = get_ipython()
930 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
932 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
931 nt.assert_equal(ip.user_ns['error'], 'hello\n')
933 nt.assert_equal(ip.user_ns['error'], 'hello\n')
932
934
933 @dec.skip_win32
935 @dec.skip_win32
934 def test_script_out_err():
936 def test_script_out_err():
935 ip = get_ipython()
937 ip = get_ipython()
936 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
938 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
937 nt.assert_equal(ip.user_ns['output'], 'hi\n')
939 nt.assert_equal(ip.user_ns['output'], 'hi\n')
938 nt.assert_equal(ip.user_ns['error'], 'hello\n')
940 nt.assert_equal(ip.user_ns['error'], 'hello\n')
939
941
940 @dec.skip_win32
942 @dec.skip_win32
941 def test_script_bg_out():
943 def test_script_bg_out():
942 ip = get_ipython()
944 ip = get_ipython()
943 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
945 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
944
946
945 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
947 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
946 ip.user_ns['output'].close()
948 ip.user_ns['output'].close()
947
949
948 @dec.skip_win32
950 @dec.skip_win32
949 def test_script_bg_err():
951 def test_script_bg_err():
950 ip = get_ipython()
952 ip = get_ipython()
951 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
953 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
952 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
954 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
953 ip.user_ns['error'].close()
955 ip.user_ns['error'].close()
954
956
955 @dec.skip_win32
957 @dec.skip_win32
956 def test_script_bg_out_err():
958 def test_script_bg_out_err():
957 ip = get_ipython()
959 ip = get_ipython()
958 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
960 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
959 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
961 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
960 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
962 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
961 ip.user_ns['output'].close()
963 ip.user_ns['output'].close()
962 ip.user_ns['error'].close()
964 ip.user_ns['error'].close()
963
965
964 def test_script_defaults():
966 def test_script_defaults():
965 ip = get_ipython()
967 ip = get_ipython()
966 for cmd in ['sh', 'bash', 'perl', 'ruby']:
968 for cmd in ['sh', 'bash', 'perl', 'ruby']:
967 try:
969 try:
968 find_cmd(cmd)
970 find_cmd(cmd)
969 except Exception:
971 except Exception:
970 pass
972 pass
971 else:
973 else:
972 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
974 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
973
975
974
976
975 @magics_class
977 @magics_class
976 class FooFoo(Magics):
978 class FooFoo(Magics):
977 """class with both %foo and %%foo magics"""
979 """class with both %foo and %%foo magics"""
978 @line_magic('foo')
980 @line_magic('foo')
979 def line_foo(self, line):
981 def line_foo(self, line):
980 "I am line foo"
982 "I am line foo"
981 pass
983 pass
982
984
983 @cell_magic("foo")
985 @cell_magic("foo")
984 def cell_foo(self, line, cell):
986 def cell_foo(self, line, cell):
985 "I am cell foo, not line foo"
987 "I am cell foo, not line foo"
986 pass
988 pass
987
989
988 def test_line_cell_info():
990 def test_line_cell_info():
989 """%%foo and %foo magics are distinguishable to inspect"""
991 """%%foo and %foo magics are distinguishable to inspect"""
990 ip = get_ipython()
992 ip = get_ipython()
991 ip.magics_manager.register(FooFoo)
993 ip.magics_manager.register(FooFoo)
992 oinfo = ip.object_inspect('foo')
994 oinfo = ip.object_inspect('foo')
993 nt.assert_true(oinfo['found'])
995 nt.assert_true(oinfo['found'])
994 nt.assert_true(oinfo['ismagic'])
996 nt.assert_true(oinfo['ismagic'])
995
997
996 oinfo = ip.object_inspect('%%foo')
998 oinfo = ip.object_inspect('%%foo')
997 nt.assert_true(oinfo['found'])
999 nt.assert_true(oinfo['found'])
998 nt.assert_true(oinfo['ismagic'])
1000 nt.assert_true(oinfo['ismagic'])
999 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1001 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1000
1002
1001 oinfo = ip.object_inspect('%foo')
1003 oinfo = ip.object_inspect('%foo')
1002 nt.assert_true(oinfo['found'])
1004 nt.assert_true(oinfo['found'])
1003 nt.assert_true(oinfo['ismagic'])
1005 nt.assert_true(oinfo['ismagic'])
1004 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1006 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1005
1007
1006 def test_multiple_magics():
1008 def test_multiple_magics():
1007 ip = get_ipython()
1009 ip = get_ipython()
1008 foo1 = FooFoo(ip)
1010 foo1 = FooFoo(ip)
1009 foo2 = FooFoo(ip)
1011 foo2 = FooFoo(ip)
1010 mm = ip.magics_manager
1012 mm = ip.magics_manager
1011 mm.register(foo1)
1013 mm.register(foo1)
1012 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
1014 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
1013 mm.register(foo2)
1015 mm.register(foo2)
1014 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
1016 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
1015
1017
1016 def test_alias_magic():
1018 def test_alias_magic():
1017 """Test %alias_magic."""
1019 """Test %alias_magic."""
1018 ip = get_ipython()
1020 ip = get_ipython()
1019 mm = ip.magics_manager
1021 mm = ip.magics_manager
1020
1022
1021 # Basic operation: both cell and line magics are created, if possible.
1023 # Basic operation: both cell and line magics are created, if possible.
1022 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1024 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1023 nt.assert_in('timeit_alias', mm.magics['line'])
1025 nt.assert_in('timeit_alias', mm.magics['line'])
1024 nt.assert_in('timeit_alias', mm.magics['cell'])
1026 nt.assert_in('timeit_alias', mm.magics['cell'])
1025
1027
1026 # --cell is specified, line magic not created.
1028 # --cell is specified, line magic not created.
1027 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1029 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1028 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1030 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1029 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1031 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1030
1032
1031 # Test that line alias is created successfully.
1033 # Test that line alias is created successfully.
1032 ip.run_line_magic('alias_magic', '--line env_alias env')
1034 ip.run_line_magic('alias_magic', '--line env_alias env')
1033 nt.assert_equal(ip.run_line_magic('env', ''),
1035 nt.assert_equal(ip.run_line_magic('env', ''),
1034 ip.run_line_magic('env_alias', ''))
1036 ip.run_line_magic('env_alias', ''))
1035
1037
1036 # Test that line alias with parameters passed in is created successfully.
1038 # Test that line alias with parameters passed in is created successfully.
1037 ip.run_line_magic('alias_magic', '--line history_alias history --params ' + shlex.quote('3'))
1039 ip.run_line_magic('alias_magic', '--line history_alias history --params ' + shlex.quote('3'))
1038 nt.assert_in('history_alias', mm.magics['line'])
1040 nt.assert_in('history_alias', mm.magics['line'])
1039
1041
1040
1042
1041 def test_save():
1043 def test_save():
1042 """Test %save."""
1044 """Test %save."""
1043 ip = get_ipython()
1045 ip = get_ipython()
1044 ip.history_manager.reset() # Clear any existing history.
1046 ip.history_manager.reset() # Clear any existing history.
1045 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
1047 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
1046 for i, cmd in enumerate(cmds, start=1):
1048 for i, cmd in enumerate(cmds, start=1):
1047 ip.history_manager.store_inputs(i, cmd)
1049 ip.history_manager.store_inputs(i, cmd)
1048 with TemporaryDirectory() as tmpdir:
1050 with TemporaryDirectory() as tmpdir:
1049 file = os.path.join(tmpdir, "testsave.py")
1051 file = os.path.join(tmpdir, "testsave.py")
1050 ip.run_line_magic("save", "%s 1-10" % file)
1052 ip.run_line_magic("save", "%s 1-10" % file)
1051 with open(file) as f:
1053 with open(file) as f:
1052 content = f.read()
1054 content = f.read()
1053 nt.assert_equal(content.count(cmds[0]), 1)
1055 nt.assert_equal(content.count(cmds[0]), 1)
1054 nt.assert_in('coding: utf-8', content)
1056 nt.assert_in('coding: utf-8', content)
1055 ip.run_line_magic("save", "-a %s 1-10" % file)
1057 ip.run_line_magic("save", "-a %s 1-10" % file)
1056 with open(file) as f:
1058 with open(file) as f:
1057 content = f.read()
1059 content = f.read()
1058 nt.assert_equal(content.count(cmds[0]), 2)
1060 nt.assert_equal(content.count(cmds[0]), 2)
1059 nt.assert_in('coding: utf-8', content)
1061 nt.assert_in('coding: utf-8', content)
1060
1062
1061
1063
1062 def test_store():
1064 def test_store():
1063 """Test %store."""
1065 """Test %store."""
1064 ip = get_ipython()
1066 ip = get_ipython()
1065 ip.run_line_magic('load_ext', 'storemagic')
1067 ip.run_line_magic('load_ext', 'storemagic')
1066
1068
1067 # make sure the storage is empty
1069 # make sure the storage is empty
1068 ip.run_line_magic('store', '-z')
1070 ip.run_line_magic('store', '-z')
1069 ip.user_ns['var'] = 42
1071 ip.user_ns['var'] = 42
1070 ip.run_line_magic('store', 'var')
1072 ip.run_line_magic('store', 'var')
1071 ip.user_ns['var'] = 39
1073 ip.user_ns['var'] = 39
1072 ip.run_line_magic('store', '-r')
1074 ip.run_line_magic('store', '-r')
1073 nt.assert_equal(ip.user_ns['var'], 42)
1075 nt.assert_equal(ip.user_ns['var'], 42)
1074
1076
1075 ip.run_line_magic('store', '-d var')
1077 ip.run_line_magic('store', '-d var')
1076 ip.user_ns['var'] = 39
1078 ip.user_ns['var'] = 39
1077 ip.run_line_magic('store' , '-r')
1079 ip.run_line_magic('store' , '-r')
1078 nt.assert_equal(ip.user_ns['var'], 39)
1080 nt.assert_equal(ip.user_ns['var'], 39)
1079
1081
1080
1082
1081 def _run_edit_test(arg_s, exp_filename=None,
1083 def _run_edit_test(arg_s, exp_filename=None,
1082 exp_lineno=-1,
1084 exp_lineno=-1,
1083 exp_contents=None,
1085 exp_contents=None,
1084 exp_is_temp=None):
1086 exp_is_temp=None):
1085 ip = get_ipython()
1087 ip = get_ipython()
1086 M = code.CodeMagics(ip)
1088 M = code.CodeMagics(ip)
1087 last_call = ['','']
1089 last_call = ['','']
1088 opts,args = M.parse_options(arg_s,'prxn:')
1090 opts,args = M.parse_options(arg_s,'prxn:')
1089 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1091 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1090
1092
1091 if exp_filename is not None:
1093 if exp_filename is not None:
1092 nt.assert_equal(exp_filename, filename)
1094 nt.assert_equal(exp_filename, filename)
1093 if exp_contents is not None:
1095 if exp_contents is not None:
1094 with io.open(filename, 'r', encoding='utf-8') as f:
1096 with io.open(filename, 'r', encoding='utf-8') as f:
1095 contents = f.read()
1097 contents = f.read()
1096 nt.assert_equal(exp_contents, contents)
1098 nt.assert_equal(exp_contents, contents)
1097 if exp_lineno != -1:
1099 if exp_lineno != -1:
1098 nt.assert_equal(exp_lineno, lineno)
1100 nt.assert_equal(exp_lineno, lineno)
1099 if exp_is_temp is not None:
1101 if exp_is_temp is not None:
1100 nt.assert_equal(exp_is_temp, is_temp)
1102 nt.assert_equal(exp_is_temp, is_temp)
1101
1103
1102
1104
1103 def test_edit_interactive():
1105 def test_edit_interactive():
1104 """%edit on interactively defined objects"""
1106 """%edit on interactively defined objects"""
1105 ip = get_ipython()
1107 ip = get_ipython()
1106 n = ip.execution_count
1108 n = ip.execution_count
1107 ip.run_cell(u"def foo(): return 1", store_history=True)
1109 ip.run_cell(u"def foo(): return 1", store_history=True)
1108
1110
1109 try:
1111 try:
1110 _run_edit_test("foo")
1112 _run_edit_test("foo")
1111 except code.InteractivelyDefined as e:
1113 except code.InteractivelyDefined as e:
1112 nt.assert_equal(e.index, n)
1114 nt.assert_equal(e.index, n)
1113 else:
1115 else:
1114 raise AssertionError("Should have raised InteractivelyDefined")
1116 raise AssertionError("Should have raised InteractivelyDefined")
1115
1117
1116
1118
1117 def test_edit_cell():
1119 def test_edit_cell():
1118 """%edit [cell id]"""
1120 """%edit [cell id]"""
1119 ip = get_ipython()
1121 ip = get_ipython()
1120
1122
1121 ip.run_cell(u"def foo(): return 1", store_history=True)
1123 ip.run_cell(u"def foo(): return 1", store_history=True)
1122
1124
1123 # test
1125 # test
1124 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1126 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1125
1127
1126 def test_bookmark():
1128 def test_bookmark():
1127 ip = get_ipython()
1129 ip = get_ipython()
1128 ip.run_line_magic('bookmark', 'bmname')
1130 ip.run_line_magic('bookmark', 'bmname')
1129 with tt.AssertPrints('bmname'):
1131 with tt.AssertPrints('bmname'):
1130 ip.run_line_magic('bookmark', '-l')
1132 ip.run_line_magic('bookmark', '-l')
1131 ip.run_line_magic('bookmark', '-d bmname')
1133 ip.run_line_magic('bookmark', '-d bmname')
1132
1134
1133 def test_ls_magic():
1135 def test_ls_magic():
1134 ip = get_ipython()
1136 ip = get_ipython()
1135 json_formatter = ip.display_formatter.formatters['application/json']
1137 json_formatter = ip.display_formatter.formatters['application/json']
1136 json_formatter.enabled = True
1138 json_formatter.enabled = True
1137 lsmagic = ip.magic('lsmagic')
1139 lsmagic = ip.magic('lsmagic')
1138 with warnings.catch_warnings(record=True) as w:
1140 with warnings.catch_warnings(record=True) as w:
1139 j = json_formatter(lsmagic)
1141 j = json_formatter(lsmagic)
1140 nt.assert_equal(sorted(j), ['cell', 'line'])
1142 nt.assert_equal(sorted(j), ['cell', 'line'])
1141 nt.assert_equal(w, []) # no warnings
1143 nt.assert_equal(w, []) # no warnings
1142
1144
1143 def test_strip_initial_indent():
1145 def test_strip_initial_indent():
1144 def sii(s):
1146 def sii(s):
1145 lines = s.splitlines()
1147 lines = s.splitlines()
1146 return '\n'.join(code.strip_initial_indent(lines))
1148 return '\n'.join(code.strip_initial_indent(lines))
1147
1149
1148 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1150 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1149 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1151 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1150 nt.assert_equal(sii("a\n b"), "a\n b")
1152 nt.assert_equal(sii("a\n b"), "a\n b")
1151
1153
1152 def test_logging_magic_quiet_from_arg():
1154 def test_logging_magic_quiet_from_arg():
1153 _ip.config.LoggingMagics.quiet = False
1155 _ip.config.LoggingMagics.quiet = False
1154 lm = logging.LoggingMagics(shell=_ip)
1156 lm = logging.LoggingMagics(shell=_ip)
1155 with TemporaryDirectory() as td:
1157 with TemporaryDirectory() as td:
1156 try:
1158 try:
1157 with tt.AssertNotPrints(re.compile("Activating.*")):
1159 with tt.AssertNotPrints(re.compile("Activating.*")):
1158 lm.logstart('-q {}'.format(
1160 lm.logstart('-q {}'.format(
1159 os.path.join(td, "quiet_from_arg.log")))
1161 os.path.join(td, "quiet_from_arg.log")))
1160 finally:
1162 finally:
1161 _ip.logger.logstop()
1163 _ip.logger.logstop()
1162
1164
1163 def test_logging_magic_quiet_from_config():
1165 def test_logging_magic_quiet_from_config():
1164 _ip.config.LoggingMagics.quiet = True
1166 _ip.config.LoggingMagics.quiet = True
1165 lm = logging.LoggingMagics(shell=_ip)
1167 lm = logging.LoggingMagics(shell=_ip)
1166 with TemporaryDirectory() as td:
1168 with TemporaryDirectory() as td:
1167 try:
1169 try:
1168 with tt.AssertNotPrints(re.compile("Activating.*")):
1170 with tt.AssertNotPrints(re.compile("Activating.*")):
1169 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1171 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1170 finally:
1172 finally:
1171 _ip.logger.logstop()
1173 _ip.logger.logstop()
1172
1174
1173
1175
1174 def test_logging_magic_not_quiet():
1176 def test_logging_magic_not_quiet():
1175 _ip.config.LoggingMagics.quiet = False
1177 _ip.config.LoggingMagics.quiet = False
1176 lm = logging.LoggingMagics(shell=_ip)
1178 lm = logging.LoggingMagics(shell=_ip)
1177 with TemporaryDirectory() as td:
1179 with TemporaryDirectory() as td:
1178 try:
1180 try:
1179 with tt.AssertPrints(re.compile("Activating.*")):
1181 with tt.AssertPrints(re.compile("Activating.*")):
1180 lm.logstart(os.path.join(td, "not_quiet.log"))
1182 lm.logstart(os.path.join(td, "not_quiet.log"))
1181 finally:
1183 finally:
1182 _ip.logger.logstop()
1184 _ip.logger.logstop()
1183
1185
1184
1186
1185 def test_time_no_var_expand():
1187 def test_time_no_var_expand():
1186 _ip.user_ns['a'] = 5
1188 _ip.user_ns['a'] = 5
1187 _ip.user_ns['b'] = []
1189 _ip.user_ns['b'] = []
1188 _ip.magic('time b.append("{a}")')
1190 _ip.magic('time b.append("{a}")')
1189 assert _ip.user_ns['b'] == ['{a}']
1191 assert _ip.user_ns['b'] == ['{a}']
1190
1192
1191
1193
1192 # this is slow, put at the end for local testing.
1194 # this is slow, put at the end for local testing.
1193 def test_timeit_arguments():
1195 def test_timeit_arguments():
1194 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1196 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1195 if sys.version_info < (3,7):
1197 if sys.version_info < (3,7):
1196 _ip.magic("timeit -n1 -r1 ('#')")
1198 _ip.magic("timeit -n1 -r1 ('#')")
1197 else:
1199 else:
1198 # 3.7 optimize no-op statement like above out, and complain there is
1200 # 3.7 optimize no-op statement like above out, and complain there is
1199 # nothing in the for loop.
1201 # nothing in the for loop.
1200 _ip.magic("timeit -n1 -r1 a=('#')")
1202 _ip.magic("timeit -n1 -r1 a=('#')")
1201
1203
1202
1204
1203 TEST_MODULE = """
1205 TEST_MODULE = """
1204 print('Loaded my_tmp')
1206 print('Loaded my_tmp')
1205 if __name__ == "__main__":
1207 if __name__ == "__main__":
1206 print('I just ran a script')
1208 print('I just ran a script')
1207 """
1209 """
1208
1210
1209
1211
1210 def test_run_module_from_import_hook():
1212 def test_run_module_from_import_hook():
1211 "Test that a module can be loaded via an import hook"
1213 "Test that a module can be loaded via an import hook"
1212 with TemporaryDirectory() as tmpdir:
1214 with TemporaryDirectory() as tmpdir:
1213 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1215 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1214 with open(fullpath, 'w') as f:
1216 with open(fullpath, 'w') as f:
1215 f.write(TEST_MODULE)
1217 f.write(TEST_MODULE)
1216
1218
1217 class MyTempImporter(object):
1219 class MyTempImporter(object):
1218 def __init__(self):
1220 def __init__(self):
1219 pass
1221 pass
1220
1222
1221 def find_module(self, fullname, path=None):
1223 def find_module(self, fullname, path=None):
1222 if 'my_tmp' in fullname:
1224 if 'my_tmp' in fullname:
1223 return self
1225 return self
1224 return None
1226 return None
1225
1227
1226 def load_module(self, name):
1228 def load_module(self, name):
1227 import imp
1229 import imp
1228 return imp.load_source('my_tmp', fullpath)
1230 return imp.load_source('my_tmp', fullpath)
1229
1231
1230 def get_code(self, fullname):
1232 def get_code(self, fullname):
1231 with open(fullpath, 'r') as f:
1233 with open(fullpath, 'r') as f:
1232 return compile(f.read(), 'foo', 'exec')
1234 return compile(f.read(), 'foo', 'exec')
1233
1235
1234 def is_package(self, __):
1236 def is_package(self, __):
1235 return False
1237 return False
1236
1238
1237 sys.meta_path.insert(0, MyTempImporter())
1239 sys.meta_path.insert(0, MyTempImporter())
1238
1240
1239 with capture_output() as captured:
1241 with capture_output() as captured:
1240 _ip.magic("run -m my_tmp")
1242 _ip.magic("run -m my_tmp")
1241 _ip.run_cell("import my_tmp")
1243 _ip.run_cell("import my_tmp")
1242
1244
1243 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1245 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1244 nt.assert_equal(output, captured.stdout)
1246 nt.assert_equal(output, captured.stdout)
1245
1247
1246 sys.meta_path.pop(0)
1248 sys.meta_path.pop(0)
@@ -1,117 +1,127 b''
1 """Tests for input manipulation machinery."""
1 """Tests for input manipulation machinery."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 import nose.tools as nt
6 import nose.tools as nt
7
7
8 from IPython.core.prefilter import AutocallChecker
8 from IPython.core.prefilter import AutocallChecker
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Tests
11 # Tests
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 def test_prefilter():
14 def test_prefilter():
15 """Test user input conversions"""
15 """Test user input conversions"""
16
16
17 # pairs of (raw, expected correct) input
17 # pairs of (raw, expected correct) input
18 pairs = [ ('2+2','2+2'),
18 pairs = [ ('2+2','2+2'),
19 ]
19 ]
20
20
21 for raw, correct in pairs:
21 for raw, correct in pairs:
22 nt.assert_equal(ip.prefilter(raw), correct)
22 nt.assert_equal(ip.prefilter(raw), correct)
23
23
24 def test_prefilter_shadowed():
24 def test_prefilter_shadowed():
25 def dummy_magic(line): pass
25 def dummy_magic(line): pass
26
26
27 prev_automagic_state = ip.automagic
27 prev_automagic_state = ip.automagic
28 ip.automagic = True
28 ip.automagic = True
29 ip.autocall = 0
29 ip.autocall = 0
30
30
31 try:
31 try:
32 # These should not be transformed - they are shadowed by other names
32 # These should not be transformed - they are shadowed by other names
33 for name in ['if', 'zip', 'get_ipython']: # keyword, builtin, global
33 for name in ['if', 'zip', 'get_ipython']: # keyword, builtin, global
34 ip.register_magic_function(dummy_magic, magic_name=name)
34 ip.register_magic_function(dummy_magic, magic_name=name)
35 res = ip.prefilter(name+' foo')
35 res = ip.prefilter(name+' foo')
36 nt.assert_equal(res, name+' foo')
36 nt.assert_equal(res, name+' foo')
37 del ip.magics_manager.magics['line'][name]
37 del ip.magics_manager.magics['line'][name]
38
38
39 # These should be transformed
39 # These should be transformed
40 for name in ['fi', 'piz', 'nohtypi_teg']:
40 for name in ['fi', 'piz', 'nohtypi_teg']:
41 ip.register_magic_function(dummy_magic, magic_name=name)
41 ip.register_magic_function(dummy_magic, magic_name=name)
42 res = ip.prefilter(name+' foo')
42 res = ip.prefilter(name+' foo')
43 nt.assert_not_equal(res, name+' foo')
43 nt.assert_not_equal(res, name+' foo')
44 del ip.magics_manager.magics['line'][name]
44 del ip.magics_manager.magics['line'][name]
45
45
46 finally:
46 finally:
47 ip.automagic = prev_automagic_state
47 ip.automagic = prev_automagic_state
48
48
49 def test_autocall_binops():
49 def test_autocall_binops():
50 """See https://github.com/ipython/ipython/issues/81"""
50 """See https://github.com/ipython/ipython/issues/81"""
51 ip.magic('autocall 2')
51 ip.magic('autocall 2')
52 f = lambda x: x
52 f = lambda x: x
53 ip.user_ns['f'] = f
53 ip.user_ns['f'] = f
54 try:
54 try:
55 nt.assert_equal(ip.prefilter('f 1'),'f(1)')
55 nt.assert_equal(ip.prefilter('f 1'),'f(1)')
56 for t in ['f +1', 'f -1']:
56 for t in ['f +1', 'f -1']:
57 nt.assert_equal(ip.prefilter(t), t)
57 nt.assert_equal(ip.prefilter(t), t)
58
58
59 # Run tests again with a more permissive exclude_regexp, which will
59 # Run tests again with a more permissive exclude_regexp, which will
60 # allow transformation of binary operations ('f -1' -> 'f(-1)').
60 # allow transformation of binary operations ('f -1' -> 'f(-1)').
61 pm = ip.prefilter_manager
61 pm = ip.prefilter_manager
62 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
62 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
63 config=pm.config)
63 config=pm.config)
64 try:
64 try:
65 ac.priority = 1
65 ac.priority = 1
66 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
66 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
67 pm.sort_checkers()
67 pm.sort_checkers()
68
68
69 nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
69 nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
70 nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
70 nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
71 finally:
71 finally:
72 pm.unregister_checker(ac)
72 pm.unregister_checker(ac)
73 finally:
73 finally:
74 ip.magic('autocall 0')
74 ip.magic('autocall 0')
75 del ip.user_ns['f']
75 del ip.user_ns['f']
76
76
77
77
78 def test_issue_114():
78 def test_issue_114():
79 """Check that multiline string literals don't expand as magic
79 """Check that multiline string literals don't expand as magic
80 see http://github.com/ipython/ipython/issues/114"""
80 see http://github.com/ipython/ipython/issues/114"""
81
81
82 template = '"""\n%s\n"""'
82 template = '"""\n%s\n"""'
83 # Store the current value of multi_line_specials and turn it off before
83 # Store the current value of multi_line_specials and turn it off before
84 # running test, since it could be true (case in which the test doesn't make
84 # running test, since it could be true (case in which the test doesn't make
85 # sense, as multiline string literals *will* expand as magic in that case).
85 # sense, as multiline string literals *will* expand as magic in that case).
86 msp = ip.prefilter_manager.multi_line_specials
86 msp = ip.prefilter_manager.multi_line_specials
87 ip.prefilter_manager.multi_line_specials = False
87 ip.prefilter_manager.multi_line_specials = False
88 try:
88 try:
89 for mgk in ip.magics_manager.lsmagic()['line']:
89 for mgk in ip.magics_manager.lsmagic()['line']:
90 raw = template % mgk
90 raw = template % mgk
91 nt.assert_equal(ip.prefilter(raw), raw)
91 nt.assert_equal(ip.prefilter(raw), raw)
92 finally:
92 finally:
93 ip.prefilter_manager.multi_line_specials = msp
93 ip.prefilter_manager.multi_line_specials = msp
94
94
95
95
96 def test_prefilter_attribute_errors():
96 def test_prefilter_attribute_errors():
97 """Capture exceptions thrown by user objects on attribute access.
97 """Capture exceptions thrown by user objects on attribute access.
98
98
99 See http://github.com/ipython/ipython/issues/988."""
99 See http://github.com/ipython/ipython/issues/988."""
100
100
101 class X(object):
101 class X(object):
102 def __getattr__(self, k):
102 def __getattr__(self, k):
103 raise ValueError('broken object')
103 raise ValueError('broken object')
104 def __call__(self, x):
104 def __call__(self, x):
105 return x
105 return x
106
106
107 # Create a callable broken object
107 # Create a callable broken object
108 ip.user_ns['x'] = X()
108 ip.user_ns['x'] = X()
109 ip.magic('autocall 2')
109 ip.magic('autocall 2')
110 try:
110 try:
111 # Even if x throws an attribute error when looking at its rewrite
111 # Even if x throws an attribute error when looking at its rewrite
112 # attribute, we should not crash. So the test here is simply making
112 # attribute, we should not crash. So the test here is simply making
113 # the prefilter call and not having an exception.
113 # the prefilter call and not having an exception.
114 ip.prefilter('x 1')
114 ip.prefilter('x 1')
115 finally:
115 finally:
116 del ip.user_ns['x']
116 del ip.user_ns['x']
117 ip.magic('autocall 0')
117 ip.magic('autocall 0')
118
119
120 def test_autocall_should_support_unicode():
121 ip.magic('autocall 2')
122 ip.user_ns['π'] = lambda x: x
123 try:
124 nt.assert_equal(ip.prefilter('π 3'),'π(3)')
125 finally:
126 ip.magic('autocall 0')
127 del ip.user_ns['π']
General Comments 0
You need to be logged in to leave comments. Login now