##// END OF EJS Templates
Merge pull request #12209 from meeseeksmachine/auto-backport-of-pr-12208-on-7.x...
Matthias Bussonnier -
r25602:3f436094 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,1223 +1,1225 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 @dec.skip_without('sqlite3')
177 @dec.skip_without('sqlite3')
178 def doctest_hist_f():
178 def doctest_hist_f():
179 """Test %hist -f with temporary filename.
179 """Test %hist -f with temporary filename.
180
180
181 In [9]: import tempfile
181 In [9]: import tempfile
182
182
183 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
183 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
184
184
185 In [11]: %hist -nl -f $tfile 3
185 In [11]: %hist -nl -f $tfile 3
186
186
187 In [13]: import os; os.unlink(tfile)
187 In [13]: import os; os.unlink(tfile)
188 """
188 """
189
189
190
190
191 @dec.skip_without('sqlite3')
191 @dec.skip_without('sqlite3')
192 def doctest_hist_r():
192 def doctest_hist_r():
193 """Test %hist -r
193 """Test %hist -r
194
194
195 XXX - This test is not recording the output correctly. For some reason, in
195 XXX - This test is not recording the output correctly. For some reason, in
196 testing mode the raw history isn't getting populated. No idea why.
196 testing mode the raw history isn't getting populated. No idea why.
197 Disabling the output checking for now, though at least we do run it.
197 Disabling the output checking for now, though at least we do run it.
198
198
199 In [1]: 'hist' in _ip.lsmagic()
199 In [1]: 'hist' in _ip.lsmagic()
200 Out[1]: True
200 Out[1]: True
201
201
202 In [2]: x=1
202 In [2]: x=1
203
203
204 In [3]: %hist -rl 2
204 In [3]: %hist -rl 2
205 x=1 # random
205 x=1 # random
206 %hist -r 2
206 %hist -r 2
207 """
207 """
208
208
209
209
210 @dec.skip_without('sqlite3')
210 @dec.skip_without('sqlite3')
211 def doctest_hist_op():
211 def doctest_hist_op():
212 """Test %hist -op
212 """Test %hist -op
213
213
214 In [1]: class b(float):
214 In [1]: class b(float):
215 ...: pass
215 ...: pass
216 ...:
216 ...:
217
217
218 In [2]: class s(object):
218 In [2]: class s(object):
219 ...: def __str__(self):
219 ...: def __str__(self):
220 ...: return 's'
220 ...: return 's'
221 ...:
221 ...:
222
222
223 In [3]:
223 In [3]:
224
224
225 In [4]: class r(b):
225 In [4]: class r(b):
226 ...: def __repr__(self):
226 ...: def __repr__(self):
227 ...: return 'r'
227 ...: return 'r'
228 ...:
228 ...:
229
229
230 In [5]: class sr(s,r): pass
230 In [5]: class sr(s,r): pass
231 ...:
231 ...:
232
232
233 In [6]:
233 In [6]:
234
234
235 In [7]: bb=b()
235 In [7]: bb=b()
236
236
237 In [8]: ss=s()
237 In [8]: ss=s()
238
238
239 In [9]: rr=r()
239 In [9]: rr=r()
240
240
241 In [10]: ssrr=sr()
241 In [10]: ssrr=sr()
242
242
243 In [11]: 4.5
243 In [11]: 4.5
244 Out[11]: 4.5
244 Out[11]: 4.5
245
245
246 In [12]: str(ss)
246 In [12]: str(ss)
247 Out[12]: 's'
247 Out[12]: 's'
248
248
249 In [13]:
249 In [13]:
250
250
251 In [14]: %hist -op
251 In [14]: %hist -op
252 >>> class b:
252 >>> class b:
253 ... pass
253 ... pass
254 ...
254 ...
255 >>> class s(b):
255 >>> class s(b):
256 ... def __str__(self):
256 ... def __str__(self):
257 ... return 's'
257 ... return 's'
258 ...
258 ...
259 >>>
259 >>>
260 >>> class r(b):
260 >>> class r(b):
261 ... def __repr__(self):
261 ... def __repr__(self):
262 ... return 'r'
262 ... return 'r'
263 ...
263 ...
264 >>> class sr(s,r): pass
264 >>> class sr(s,r): pass
265 >>>
265 >>>
266 >>> bb=b()
266 >>> bb=b()
267 >>> ss=s()
267 >>> ss=s()
268 >>> rr=r()
268 >>> rr=r()
269 >>> ssrr=sr()
269 >>> ssrr=sr()
270 >>> 4.5
270 >>> 4.5
271 4.5
271 4.5
272 >>> str(ss)
272 >>> str(ss)
273 's'
273 's'
274 >>>
274 >>>
275 """
275 """
276
276
277 def test_hist_pof():
277 def test_hist_pof():
278 ip = get_ipython()
278 ip = get_ipython()
279 ip.run_cell(u"1+2", store_history=True)
279 ip.run_cell(u"1+2", store_history=True)
280 #raise Exception(ip.history_manager.session_number)
280 #raise Exception(ip.history_manager.session_number)
281 #raise Exception(list(ip.history_manager._get_range_session()))
281 #raise Exception(list(ip.history_manager._get_range_session()))
282 with TemporaryDirectory() as td:
282 with TemporaryDirectory() as td:
283 tf = os.path.join(td, 'hist.py')
283 tf = os.path.join(td, 'hist.py')
284 ip.run_line_magic('history', '-pof %s' % tf)
284 ip.run_line_magic('history', '-pof %s' % tf)
285 assert os.path.isfile(tf)
285 assert os.path.isfile(tf)
286
286
287
287
288 @dec.skip_without('sqlite3')
288 @dec.skip_without('sqlite3')
289 def test_macro():
289 def test_macro():
290 ip = get_ipython()
290 ip = get_ipython()
291 ip.history_manager.reset() # Clear any existing history.
291 ip.history_manager.reset() # Clear any existing history.
292 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
292 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
293 for i, cmd in enumerate(cmds, start=1):
293 for i, cmd in enumerate(cmds, start=1):
294 ip.history_manager.store_inputs(i, cmd)
294 ip.history_manager.store_inputs(i, cmd)
295 ip.magic("macro test 1-3")
295 ip.magic("macro test 1-3")
296 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
296 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
297
297
298 # List macros
298 # List macros
299 nt.assert_in("test", ip.magic("macro"))
299 nt.assert_in("test", ip.magic("macro"))
300
300
301
301
302 @dec.skip_without('sqlite3')
302 @dec.skip_without('sqlite3')
303 def test_macro_run():
303 def test_macro_run():
304 """Test that we can run a multi-line macro successfully."""
304 """Test that we can run a multi-line macro successfully."""
305 ip = get_ipython()
305 ip = get_ipython()
306 ip.history_manager.reset()
306 ip.history_manager.reset()
307 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
307 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
308 for cmd in cmds:
308 for cmd in cmds:
309 ip.run_cell(cmd, store_history=True)
309 ip.run_cell(cmd, store_history=True)
310 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint(a)\n")
310 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint(a)\n")
311 with tt.AssertPrints("12"):
311 with tt.AssertPrints("12"):
312 ip.run_cell("test")
312 ip.run_cell("test")
313 with tt.AssertPrints("13"):
313 with tt.AssertPrints("13"):
314 ip.run_cell("test")
314 ip.run_cell("test")
315
315
316
316
317 def test_magic_magic():
317 def test_magic_magic():
318 """Test %magic"""
318 """Test %magic"""
319 ip = get_ipython()
319 ip = get_ipython()
320 with capture_output() as captured:
320 with capture_output() as captured:
321 ip.magic("magic")
321 ip.magic("magic")
322
322
323 stdout = captured.stdout
323 stdout = captured.stdout
324 nt.assert_in('%magic', stdout)
324 nt.assert_in('%magic', stdout)
325 nt.assert_in('IPython', stdout)
325 nt.assert_in('IPython', stdout)
326 nt.assert_in('Available', stdout)
326 nt.assert_in('Available', stdout)
327
327
328
328
329 @dec.skipif_not_numpy
329 @dec.skipif_not_numpy
330 def test_numpy_reset_array_undec():
330 def test_numpy_reset_array_undec():
331 "Test '%reset array' functionality"
331 "Test '%reset array' functionality"
332 _ip.ex('import numpy as np')
332 _ip.ex('import numpy as np')
333 _ip.ex('a = np.empty(2)')
333 _ip.ex('a = np.empty(2)')
334 nt.assert_in('a', _ip.user_ns)
334 nt.assert_in('a', _ip.user_ns)
335 _ip.magic('reset -f array')
335 _ip.magic('reset -f array')
336 nt.assert_not_in('a', _ip.user_ns)
336 nt.assert_not_in('a', _ip.user_ns)
337
337
338 def test_reset_out():
338 def test_reset_out():
339 "Test '%reset out' magic"
339 "Test '%reset out' magic"
340 _ip.run_cell("parrot = 'dead'", store_history=True)
340 _ip.run_cell("parrot = 'dead'", store_history=True)
341 # test '%reset -f out', make an Out prompt
341 # test '%reset -f out', make an Out prompt
342 _ip.run_cell("parrot", store_history=True)
342 _ip.run_cell("parrot", store_history=True)
343 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
343 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
344 _ip.magic('reset -f out')
344 _ip.magic('reset -f out')
345 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
345 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
346 nt.assert_equal(len(_ip.user_ns['Out']), 0)
346 nt.assert_equal(len(_ip.user_ns['Out']), 0)
347
347
348 def test_reset_in():
348 def test_reset_in():
349 "Test '%reset in' magic"
349 "Test '%reset in' magic"
350 # test '%reset -f in'
350 # test '%reset -f in'
351 _ip.run_cell("parrot", store_history=True)
351 _ip.run_cell("parrot", store_history=True)
352 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
352 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
353 _ip.magic('%reset -f in')
353 _ip.magic('%reset -f in')
354 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
354 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
355 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
355 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
356
356
357 def test_reset_dhist():
357 def test_reset_dhist():
358 "Test '%reset dhist' magic"
358 "Test '%reset dhist' magic"
359 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
359 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
360 _ip.magic('cd ' + os.path.dirname(nt.__file__))
360 _ip.magic('cd ' + os.path.dirname(nt.__file__))
361 _ip.magic('cd -')
361 _ip.magic('cd -')
362 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
362 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
363 _ip.magic('reset -f dhist')
363 _ip.magic('reset -f dhist')
364 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
364 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
365 _ip.run_cell("_dh = [d for d in tmp]") #restore
365 _ip.run_cell("_dh = [d for d in tmp]") #restore
366
366
367 def test_reset_in_length():
367 def test_reset_in_length():
368 "Test that '%reset in' preserves In[] length"
368 "Test that '%reset in' preserves In[] length"
369 _ip.run_cell("print 'foo'")
369 _ip.run_cell("print 'foo'")
370 _ip.run_cell("reset -f in")
370 _ip.run_cell("reset -f in")
371 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
371 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
372
372
373 class TestResetErrors(TestCase):
373 class TestResetErrors(TestCase):
374
374
375 def test_reset_redefine(self):
375 def test_reset_redefine(self):
376
376
377 @magics_class
377 @magics_class
378 class KernelMagics(Magics):
378 class KernelMagics(Magics):
379 @line_magic
379 @line_magic
380 def less(self, shell): pass
380 def less(self, shell): pass
381
381
382 _ip.register_magics(KernelMagics)
382 _ip.register_magics(KernelMagics)
383
383
384 with self.assertLogs() as cm:
384 with self.assertLogs() as cm:
385 # hack, we want to just capture logs, but assertLogs fails if not
385 # hack, we want to just capture logs, but assertLogs fails if not
386 # logs get produce.
386 # logs get produce.
387 # so log one things we ignore.
387 # so log one things we ignore.
388 import logging as log_mod
388 import logging as log_mod
389 log = log_mod.getLogger()
389 log = log_mod.getLogger()
390 log.info('Nothing')
390 log.info('Nothing')
391 # end hack.
391 # end hack.
392 _ip.run_cell("reset -f")
392 _ip.run_cell("reset -f")
393
393
394 assert len(cm.output) == 1
394 assert len(cm.output) == 1
395 for out in cm.output:
395 for out in cm.output:
396 assert "Invalid alias" not in out
396 assert "Invalid alias" not in out
397
397
398 def test_tb_syntaxerror():
398 def test_tb_syntaxerror():
399 """test %tb after a SyntaxError"""
399 """test %tb after a SyntaxError"""
400 ip = get_ipython()
400 ip = get_ipython()
401 ip.run_cell("for")
401 ip.run_cell("for")
402
402
403 # trap and validate stdout
403 # trap and validate stdout
404 save_stdout = sys.stdout
404 save_stdout = sys.stdout
405 try:
405 try:
406 sys.stdout = StringIO()
406 sys.stdout = StringIO()
407 ip.run_cell("%tb")
407 ip.run_cell("%tb")
408 out = sys.stdout.getvalue()
408 out = sys.stdout.getvalue()
409 finally:
409 finally:
410 sys.stdout = save_stdout
410 sys.stdout = save_stdout
411 # trim output, and only check the last line
411 # trim output, and only check the last line
412 last_line = out.rstrip().splitlines()[-1].strip()
412 last_line = out.rstrip().splitlines()[-1].strip()
413 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
413 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
414
414
415
415
416 def test_time():
416 def test_time():
417 ip = get_ipython()
417 ip = get_ipython()
418
418
419 with tt.AssertPrints("Wall time: "):
419 with tt.AssertPrints("Wall time: "):
420 ip.run_cell("%time None")
420 ip.run_cell("%time None")
421
421
422 ip.run_cell("def f(kmjy):\n"
422 ip.run_cell("def f(kmjy):\n"
423 " %time print (2*kmjy)")
423 " %time print (2*kmjy)")
424
424
425 with tt.AssertPrints("Wall time: "):
425 with tt.AssertPrints("Wall time: "):
426 with tt.AssertPrints("hihi", suppress=False):
426 with tt.AssertPrints("hihi", suppress=False):
427 ip.run_cell("f('hi')")
427 ip.run_cell("f('hi')")
428
428
429 def test_time_last_not_expression():
429 def test_time_last_not_expression():
430 ip.run_cell("%%time\n"
430 ip.run_cell("%%time\n"
431 "var_1 = 1\n"
431 "var_1 = 1\n"
432 "var_2 = 2\n")
432 "var_2 = 2\n")
433 assert ip.user_ns['var_1'] == 1
433 assert ip.user_ns['var_1'] == 1
434 del ip.user_ns['var_1']
434 del ip.user_ns['var_1']
435 assert ip.user_ns['var_2'] == 2
435 assert ip.user_ns['var_2'] == 2
436 del ip.user_ns['var_2']
436 del ip.user_ns['var_2']
437
437
438
438
439 @dec.skip_win32
439 @dec.skip_win32
440 def test_time2():
440 def test_time2():
441 ip = get_ipython()
441 ip = get_ipython()
442
442
443 with tt.AssertPrints("CPU times: user "):
443 with tt.AssertPrints("CPU times: user "):
444 ip.run_cell("%time None")
444 ip.run_cell("%time None")
445
445
446 def test_time3():
446 def test_time3():
447 """Erroneous magic function calls, issue gh-3334"""
447 """Erroneous magic function calls, issue gh-3334"""
448 ip = get_ipython()
448 ip = get_ipython()
449 ip.user_ns.pop('run', None)
449 ip.user_ns.pop('run', None)
450
450
451 with tt.AssertNotPrints("not found", channel='stderr'):
451 with tt.AssertNotPrints("not found", channel='stderr'):
452 ip.run_cell("%%time\n"
452 ip.run_cell("%%time\n"
453 "run = 0\n"
453 "run = 0\n"
454 "run += 1")
454 "run += 1")
455
455
456 def test_multiline_time():
456 def test_multiline_time():
457 """Make sure last statement from time return a value."""
457 """Make sure last statement from time return a value."""
458 ip = get_ipython()
458 ip = get_ipython()
459 ip.user_ns.pop('run', None)
459 ip.user_ns.pop('run', None)
460
460
461 ip.run_cell(dedent("""\
461 ip.run_cell(dedent("""\
462 %%time
462 %%time
463 a = "ho"
463 a = "ho"
464 b = "hey"
464 b = "hey"
465 a+b
465 a+b
466 """))
466 """))
467 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
467 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
468
468
469 def test_time_local_ns():
469 def test_time_local_ns():
470 """
470 """
471 Test that local_ns is actually global_ns when running a cell magic
471 Test that local_ns is actually global_ns when running a cell magic
472 """
472 """
473 ip = get_ipython()
473 ip = get_ipython()
474 ip.run_cell("%%time\n"
474 ip.run_cell("%%time\n"
475 "myvar = 1")
475 "myvar = 1")
476 nt.assert_equal(ip.user_ns['myvar'], 1)
476 nt.assert_equal(ip.user_ns['myvar'], 1)
477 del ip.user_ns['myvar']
477 del ip.user_ns['myvar']
478
478
479 def test_doctest_mode():
479 def test_doctest_mode():
480 "Toggle doctest_mode twice, it should be a no-op and run without error"
480 "Toggle doctest_mode twice, it should be a no-op and run without error"
481 _ip.magic('doctest_mode')
481 _ip.magic('doctest_mode')
482 _ip.magic('doctest_mode')
482 _ip.magic('doctest_mode')
483
483
484
484
485 def test_parse_options():
485 def test_parse_options():
486 """Tests for basic options parsing in magics."""
486 """Tests for basic options parsing in magics."""
487 # These are only the most minimal of tests, more should be added later. At
487 # These are only the most minimal of tests, more should be added later. At
488 # the very least we check that basic text/unicode calls work OK.
488 # the very least we check that basic text/unicode calls work OK.
489 m = DummyMagics(_ip)
489 m = DummyMagics(_ip)
490 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
490 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
491 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
491 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
492
492
493
493
494 def test_dirops():
494 def test_dirops():
495 """Test various directory handling operations."""
495 """Test various directory handling operations."""
496 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
496 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
497 curpath = os.getcwd
497 curpath = os.getcwd
498 startdir = os.getcwd()
498 startdir = os.getcwd()
499 ipdir = os.path.realpath(_ip.ipython_dir)
499 ipdir = os.path.realpath(_ip.ipython_dir)
500 try:
500 try:
501 _ip.magic('cd "%s"' % ipdir)
501 _ip.magic('cd "%s"' % ipdir)
502 nt.assert_equal(curpath(), ipdir)
502 nt.assert_equal(curpath(), ipdir)
503 _ip.magic('cd -')
503 _ip.magic('cd -')
504 nt.assert_equal(curpath(), startdir)
504 nt.assert_equal(curpath(), startdir)
505 _ip.magic('pushd "%s"' % ipdir)
505 _ip.magic('pushd "%s"' % ipdir)
506 nt.assert_equal(curpath(), ipdir)
506 nt.assert_equal(curpath(), ipdir)
507 _ip.magic('popd')
507 _ip.magic('popd')
508 nt.assert_equal(curpath(), startdir)
508 nt.assert_equal(curpath(), startdir)
509 finally:
509 finally:
510 os.chdir(startdir)
510 os.chdir(startdir)
511
511
512
512
513 def test_cd_force_quiet():
513 def test_cd_force_quiet():
514 """Test OSMagics.cd_force_quiet option"""
514 """Test OSMagics.cd_force_quiet option"""
515 _ip.config.OSMagics.cd_force_quiet = True
515 _ip.config.OSMagics.cd_force_quiet = True
516 osmagics = osm.OSMagics(shell=_ip)
516 osmagics = osm.OSMagics(shell=_ip)
517
517
518 startdir = os.getcwd()
518 startdir = os.getcwd()
519 ipdir = os.path.realpath(_ip.ipython_dir)
519 ipdir = os.path.realpath(_ip.ipython_dir)
520
520
521 try:
521 try:
522 with tt.AssertNotPrints(ipdir):
522 with tt.AssertNotPrints(ipdir):
523 osmagics.cd('"%s"' % ipdir)
523 osmagics.cd('"%s"' % ipdir)
524 with tt.AssertNotPrints(startdir):
524 with tt.AssertNotPrints(startdir):
525 osmagics.cd('-')
525 osmagics.cd('-')
526 finally:
526 finally:
527 os.chdir(startdir)
527 os.chdir(startdir)
528
528
529
529
530 def test_xmode():
530 def test_xmode():
531 # Calling xmode three times should be a no-op
531 # Calling xmode three times should be a no-op
532 xmode = _ip.InteractiveTB.mode
532 xmode = _ip.InteractiveTB.mode
533 for i in range(4):
533 for i in range(4):
534 _ip.magic("xmode")
534 _ip.magic("xmode")
535 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
535 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
536
536
537 def test_reset_hard():
537 def test_reset_hard():
538 monitor = []
538 monitor = []
539 class A(object):
539 class A(object):
540 def __del__(self):
540 def __del__(self):
541 monitor.append(1)
541 monitor.append(1)
542 def __repr__(self):
542 def __repr__(self):
543 return "<A instance>"
543 return "<A instance>"
544
544
545 _ip.user_ns["a"] = A()
545 _ip.user_ns["a"] = A()
546 _ip.run_cell("a")
546 _ip.run_cell("a")
547
547
548 nt.assert_equal(monitor, [])
548 nt.assert_equal(monitor, [])
549 _ip.magic("reset -f")
549 _ip.magic("reset -f")
550 nt.assert_equal(monitor, [1])
550 nt.assert_equal(monitor, [1])
551
551
552 class TestXdel(tt.TempFileMixin):
552 class TestXdel(tt.TempFileMixin):
553 def test_xdel(self):
553 def test_xdel(self):
554 """Test that references from %run are cleared by xdel."""
554 """Test that references from %run are cleared by xdel."""
555 src = ("class A(object):\n"
555 src = ("class A(object):\n"
556 " monitor = []\n"
556 " monitor = []\n"
557 " def __del__(self):\n"
557 " def __del__(self):\n"
558 " self.monitor.append(1)\n"
558 " self.monitor.append(1)\n"
559 "a = A()\n")
559 "a = A()\n")
560 self.mktmp(src)
560 self.mktmp(src)
561 # %run creates some hidden references...
561 # %run creates some hidden references...
562 _ip.magic("run %s" % self.fname)
562 _ip.magic("run %s" % self.fname)
563 # ... as does the displayhook.
563 # ... as does the displayhook.
564 _ip.run_cell("a")
564 _ip.run_cell("a")
565
565
566 monitor = _ip.user_ns["A"].monitor
566 monitor = _ip.user_ns["A"].monitor
567 nt.assert_equal(monitor, [])
567 nt.assert_equal(monitor, [])
568
568
569 _ip.magic("xdel a")
569 _ip.magic("xdel a")
570
570
571 # Check that a's __del__ method has been called.
571 # Check that a's __del__ method has been called.
572 nt.assert_equal(monitor, [1])
572 nt.assert_equal(monitor, [1])
573
573
574 def doctest_who():
574 def doctest_who():
575 """doctest for %who
575 """doctest for %who
576
576
577 In [1]: %reset -f
577 In [1]: %reset -f
578
578
579 In [2]: alpha = 123
579 In [2]: alpha = 123
580
580
581 In [3]: beta = 'beta'
581 In [3]: beta = 'beta'
582
582
583 In [4]: %who int
583 In [4]: %who int
584 alpha
584 alpha
585
585
586 In [5]: %who str
586 In [5]: %who str
587 beta
587 beta
588
588
589 In [6]: %whos
589 In [6]: %whos
590 Variable Type Data/Info
590 Variable Type Data/Info
591 ----------------------------
591 ----------------------------
592 alpha int 123
592 alpha int 123
593 beta str beta
593 beta str beta
594
594
595 In [7]: %who_ls
595 In [7]: %who_ls
596 Out[7]: ['alpha', 'beta']
596 Out[7]: ['alpha', 'beta']
597 """
597 """
598
598
599 def test_whos():
599 def test_whos():
600 """Check that whos is protected against objects where repr() fails."""
600 """Check that whos is protected against objects where repr() fails."""
601 class A(object):
601 class A(object):
602 def __repr__(self):
602 def __repr__(self):
603 raise Exception()
603 raise Exception()
604 _ip.user_ns['a'] = A()
604 _ip.user_ns['a'] = A()
605 _ip.magic("whos")
605 _ip.magic("whos")
606
606
607 def doctest_precision():
607 def doctest_precision():
608 """doctest for %precision
608 """doctest for %precision
609
609
610 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
610 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
611
611
612 In [2]: %precision 5
612 In [2]: %precision 5
613 Out[2]: '%.5f'
613 Out[2]: '%.5f'
614
614
615 In [3]: f.float_format
615 In [3]: f.float_format
616 Out[3]: '%.5f'
616 Out[3]: '%.5f'
617
617
618 In [4]: %precision %e
618 In [4]: %precision %e
619 Out[4]: '%e'
619 Out[4]: '%e'
620
620
621 In [5]: f(3.1415927)
621 In [5]: f(3.1415927)
622 Out[5]: '3.141593e+00'
622 Out[5]: '3.141593e+00'
623 """
623 """
624
624
625 def test_psearch():
625 def test_psearch():
626 with tt.AssertPrints("dict.fromkeys"):
626 with tt.AssertPrints("dict.fromkeys"):
627 _ip.run_cell("dict.fr*?")
627 _ip.run_cell("dict.fr*?")
628 with tt.AssertPrints("π.is_integer"):
629 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
628
630
629 def test_timeit_shlex():
631 def test_timeit_shlex():
630 """test shlex issues with timeit (#1109)"""
632 """test shlex issues with timeit (#1109)"""
631 _ip.ex("def f(*a,**kw): pass")
633 _ip.ex("def f(*a,**kw): pass")
632 _ip.magic('timeit -n1 "this is a bug".count(" ")')
634 _ip.magic('timeit -n1 "this is a bug".count(" ")')
633 _ip.magic('timeit -r1 -n1 f(" ", 1)')
635 _ip.magic('timeit -r1 -n1 f(" ", 1)')
634 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
636 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
635 _ip.magic('timeit -r1 -n1 ("a " + "b")')
637 _ip.magic('timeit -r1 -n1 ("a " + "b")')
636 _ip.magic('timeit -r1 -n1 f("a " + "b")')
638 _ip.magic('timeit -r1 -n1 f("a " + "b")')
637 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
639 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
638
640
639
641
640 def test_timeit_special_syntax():
642 def test_timeit_special_syntax():
641 "Test %%timeit with IPython special syntax"
643 "Test %%timeit with IPython special syntax"
642 @register_line_magic
644 @register_line_magic
643 def lmagic(line):
645 def lmagic(line):
644 ip = get_ipython()
646 ip = get_ipython()
645 ip.user_ns['lmagic_out'] = line
647 ip.user_ns['lmagic_out'] = line
646
648
647 # line mode test
649 # line mode test
648 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
650 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
649 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
651 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
650 # cell mode test
652 # cell mode test
651 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
653 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
652 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
654 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
653
655
654 def test_timeit_return():
656 def test_timeit_return():
655 """
657 """
656 test whether timeit -o return object
658 test whether timeit -o return object
657 """
659 """
658
660
659 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
661 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
660 assert(res is not None)
662 assert(res is not None)
661
663
662 def test_timeit_quiet():
664 def test_timeit_quiet():
663 """
665 """
664 test quiet option of timeit magic
666 test quiet option of timeit magic
665 """
667 """
666 with tt.AssertNotPrints("loops"):
668 with tt.AssertNotPrints("loops"):
667 _ip.run_cell("%timeit -n1 -r1 -q 1")
669 _ip.run_cell("%timeit -n1 -r1 -q 1")
668
670
669 def test_timeit_return_quiet():
671 def test_timeit_return_quiet():
670 with tt.AssertNotPrints("loops"):
672 with tt.AssertNotPrints("loops"):
671 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
673 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
672 assert (res is not None)
674 assert (res is not None)
673
675
674 def test_timeit_invalid_return():
676 def test_timeit_invalid_return():
675 with nt.assert_raises_regex(SyntaxError, "outside function"):
677 with nt.assert_raises_regex(SyntaxError, "outside function"):
676 _ip.run_line_magic('timeit', 'return')
678 _ip.run_line_magic('timeit', 'return')
677
679
678 @dec.skipif(execution.profile is None)
680 @dec.skipif(execution.profile is None)
679 def test_prun_special_syntax():
681 def test_prun_special_syntax():
680 "Test %%prun with IPython special syntax"
682 "Test %%prun with IPython special syntax"
681 @register_line_magic
683 @register_line_magic
682 def lmagic(line):
684 def lmagic(line):
683 ip = get_ipython()
685 ip = get_ipython()
684 ip.user_ns['lmagic_out'] = line
686 ip.user_ns['lmagic_out'] = line
685
687
686 # line mode test
688 # line mode test
687 _ip.run_line_magic('prun', '-q %lmagic my line')
689 _ip.run_line_magic('prun', '-q %lmagic my line')
688 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
690 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
689 # cell mode test
691 # cell mode test
690 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
692 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
691 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
693 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
692
694
693 @dec.skipif(execution.profile is None)
695 @dec.skipif(execution.profile is None)
694 def test_prun_quotes():
696 def test_prun_quotes():
695 "Test that prun does not clobber string escapes (GH #1302)"
697 "Test that prun does not clobber string escapes (GH #1302)"
696 _ip.magic(r"prun -q x = '\t'")
698 _ip.magic(r"prun -q x = '\t'")
697 nt.assert_equal(_ip.user_ns['x'], '\t')
699 nt.assert_equal(_ip.user_ns['x'], '\t')
698
700
699 def test_extension():
701 def test_extension():
700 # Debugging information for failures of this test
702 # Debugging information for failures of this test
701 print('sys.path:')
703 print('sys.path:')
702 for p in sys.path:
704 for p in sys.path:
703 print(' ', p)
705 print(' ', p)
704 print('CWD', os.getcwd())
706 print('CWD', os.getcwd())
705
707
706 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
708 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
707 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
709 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
708 sys.path.insert(0, daft_path)
710 sys.path.insert(0, daft_path)
709 try:
711 try:
710 _ip.user_ns.pop('arq', None)
712 _ip.user_ns.pop('arq', None)
711 invalidate_caches() # Clear import caches
713 invalidate_caches() # Clear import caches
712 _ip.magic("load_ext daft_extension")
714 _ip.magic("load_ext daft_extension")
713 nt.assert_equal(_ip.user_ns['arq'], 185)
715 nt.assert_equal(_ip.user_ns['arq'], 185)
714 _ip.magic("unload_ext daft_extension")
716 _ip.magic("unload_ext daft_extension")
715 assert 'arq' not in _ip.user_ns
717 assert 'arq' not in _ip.user_ns
716 finally:
718 finally:
717 sys.path.remove(daft_path)
719 sys.path.remove(daft_path)
718
720
719
721
720 def test_notebook_export_json():
722 def test_notebook_export_json():
721 _ip = get_ipython()
723 _ip = get_ipython()
722 _ip.history_manager.reset() # Clear any existing history.
724 _ip.history_manager.reset() # Clear any existing history.
723 cmds = [u"a=1", u"def b():\n return a**2", u"print('noël, été', b())"]
725 cmds = [u"a=1", u"def b():\n return a**2", u"print('noël, été', b())"]
724 for i, cmd in enumerate(cmds, start=1):
726 for i, cmd in enumerate(cmds, start=1):
725 _ip.history_manager.store_inputs(i, cmd)
727 _ip.history_manager.store_inputs(i, cmd)
726 with TemporaryDirectory() as td:
728 with TemporaryDirectory() as td:
727 outfile = os.path.join(td, "nb.ipynb")
729 outfile = os.path.join(td, "nb.ipynb")
728 _ip.magic("notebook -e %s" % outfile)
730 _ip.magic("notebook -e %s" % outfile)
729
731
730
732
731 class TestEnv(TestCase):
733 class TestEnv(TestCase):
732
734
733 def test_env(self):
735 def test_env(self):
734 env = _ip.magic("env")
736 env = _ip.magic("env")
735 self.assertTrue(isinstance(env, dict))
737 self.assertTrue(isinstance(env, dict))
736
738
737 def test_env_secret(self):
739 def test_env_secret(self):
738 env = _ip.magic("env")
740 env = _ip.magic("env")
739 hidden = "<hidden>"
741 hidden = "<hidden>"
740 with mock.patch.dict(
742 with mock.patch.dict(
741 os.environ,
743 os.environ,
742 {
744 {
743 "API_KEY": "abc123",
745 "API_KEY": "abc123",
744 "SECRET_THING": "ssshhh",
746 "SECRET_THING": "ssshhh",
745 "JUPYTER_TOKEN": "",
747 "JUPYTER_TOKEN": "",
746 "VAR": "abc"
748 "VAR": "abc"
747 }
749 }
748 ):
750 ):
749 env = _ip.magic("env")
751 env = _ip.magic("env")
750 assert env["API_KEY"] == hidden
752 assert env["API_KEY"] == hidden
751 assert env["SECRET_THING"] == hidden
753 assert env["SECRET_THING"] == hidden
752 assert env["JUPYTER_TOKEN"] == hidden
754 assert env["JUPYTER_TOKEN"] == hidden
753 assert env["VAR"] == "abc"
755 assert env["VAR"] == "abc"
754
756
755 def test_env_get_set_simple(self):
757 def test_env_get_set_simple(self):
756 env = _ip.magic("env var val1")
758 env = _ip.magic("env var val1")
757 self.assertEqual(env, None)
759 self.assertEqual(env, None)
758 self.assertEqual(os.environ['var'], 'val1')
760 self.assertEqual(os.environ['var'], 'val1')
759 self.assertEqual(_ip.magic("env var"), 'val1')
761 self.assertEqual(_ip.magic("env var"), 'val1')
760 env = _ip.magic("env var=val2")
762 env = _ip.magic("env var=val2")
761 self.assertEqual(env, None)
763 self.assertEqual(env, None)
762 self.assertEqual(os.environ['var'], 'val2')
764 self.assertEqual(os.environ['var'], 'val2')
763
765
764 def test_env_get_set_complex(self):
766 def test_env_get_set_complex(self):
765 env = _ip.magic("env var 'val1 '' 'val2")
767 env = _ip.magic("env var 'val1 '' 'val2")
766 self.assertEqual(env, None)
768 self.assertEqual(env, None)
767 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
769 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
768 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
770 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
769 env = _ip.magic('env var=val2 val3="val4')
771 env = _ip.magic('env var=val2 val3="val4')
770 self.assertEqual(env, None)
772 self.assertEqual(env, None)
771 self.assertEqual(os.environ['var'], 'val2 val3="val4')
773 self.assertEqual(os.environ['var'], 'val2 val3="val4')
772
774
773 def test_env_set_bad_input(self):
775 def test_env_set_bad_input(self):
774 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
776 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
775
777
776 def test_env_set_whitespace(self):
778 def test_env_set_whitespace(self):
777 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
779 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
778
780
779
781
780 class CellMagicTestCase(TestCase):
782 class CellMagicTestCase(TestCase):
781
783
782 def check_ident(self, magic):
784 def check_ident(self, magic):
783 # Manually called, we get the result
785 # Manually called, we get the result
784 out = _ip.run_cell_magic(magic, 'a', 'b')
786 out = _ip.run_cell_magic(magic, 'a', 'b')
785 nt.assert_equal(out, ('a','b'))
787 nt.assert_equal(out, ('a','b'))
786 # Via run_cell, it goes into the user's namespace via displayhook
788 # Via run_cell, it goes into the user's namespace via displayhook
787 _ip.run_cell('%%' + magic +' c\nd\n')
789 _ip.run_cell('%%' + magic +' c\nd\n')
788 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
790 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
789
791
790 def test_cell_magic_func_deco(self):
792 def test_cell_magic_func_deco(self):
791 "Cell magic using simple decorator"
793 "Cell magic using simple decorator"
792 @register_cell_magic
794 @register_cell_magic
793 def cellm(line, cell):
795 def cellm(line, cell):
794 return line, cell
796 return line, cell
795
797
796 self.check_ident('cellm')
798 self.check_ident('cellm')
797
799
798 def test_cell_magic_reg(self):
800 def test_cell_magic_reg(self):
799 "Cell magic manually registered"
801 "Cell magic manually registered"
800 def cellm(line, cell):
802 def cellm(line, cell):
801 return line, cell
803 return line, cell
802
804
803 _ip.register_magic_function(cellm, 'cell', 'cellm2')
805 _ip.register_magic_function(cellm, 'cell', 'cellm2')
804 self.check_ident('cellm2')
806 self.check_ident('cellm2')
805
807
806 def test_cell_magic_class(self):
808 def test_cell_magic_class(self):
807 "Cell magics declared via a class"
809 "Cell magics declared via a class"
808 @magics_class
810 @magics_class
809 class MyMagics(Magics):
811 class MyMagics(Magics):
810
812
811 @cell_magic
813 @cell_magic
812 def cellm3(self, line, cell):
814 def cellm3(self, line, cell):
813 return line, cell
815 return line, cell
814
816
815 _ip.register_magics(MyMagics)
817 _ip.register_magics(MyMagics)
816 self.check_ident('cellm3')
818 self.check_ident('cellm3')
817
819
818 def test_cell_magic_class2(self):
820 def test_cell_magic_class2(self):
819 "Cell magics declared via a class, #2"
821 "Cell magics declared via a class, #2"
820 @magics_class
822 @magics_class
821 class MyMagics2(Magics):
823 class MyMagics2(Magics):
822
824
823 @cell_magic('cellm4')
825 @cell_magic('cellm4')
824 def cellm33(self, line, cell):
826 def cellm33(self, line, cell):
825 return line, cell
827 return line, cell
826
828
827 _ip.register_magics(MyMagics2)
829 _ip.register_magics(MyMagics2)
828 self.check_ident('cellm4')
830 self.check_ident('cellm4')
829 # Check that nothing is registered as 'cellm33'
831 # Check that nothing is registered as 'cellm33'
830 c33 = _ip.find_cell_magic('cellm33')
832 c33 = _ip.find_cell_magic('cellm33')
831 nt.assert_equal(c33, None)
833 nt.assert_equal(c33, None)
832
834
833 def test_file():
835 def test_file():
834 """Basic %%writefile"""
836 """Basic %%writefile"""
835 ip = get_ipython()
837 ip = get_ipython()
836 with TemporaryDirectory() as td:
838 with TemporaryDirectory() as td:
837 fname = os.path.join(td, 'file1')
839 fname = os.path.join(td, 'file1')
838 ip.run_cell_magic("writefile", fname, u'\n'.join([
840 ip.run_cell_magic("writefile", fname, u'\n'.join([
839 'line1',
841 'line1',
840 'line2',
842 'line2',
841 ]))
843 ]))
842 with open(fname) as f:
844 with open(fname) as f:
843 s = f.read()
845 s = f.read()
844 nt.assert_in('line1\n', s)
846 nt.assert_in('line1\n', s)
845 nt.assert_in('line2', s)
847 nt.assert_in('line2', s)
846
848
847 @dec.skip_win32
849 @dec.skip_win32
848 def test_file_single_quote():
850 def test_file_single_quote():
849 """Basic %%writefile with embedded single quotes"""
851 """Basic %%writefile with embedded single quotes"""
850 ip = get_ipython()
852 ip = get_ipython()
851 with TemporaryDirectory() as td:
853 with TemporaryDirectory() as td:
852 fname = os.path.join(td, '\'file1\'')
854 fname = os.path.join(td, '\'file1\'')
853 ip.run_cell_magic("writefile", fname, u'\n'.join([
855 ip.run_cell_magic("writefile", fname, u'\n'.join([
854 'line1',
856 'line1',
855 'line2',
857 'line2',
856 ]))
858 ]))
857 with open(fname) as f:
859 with open(fname) as f:
858 s = f.read()
860 s = f.read()
859 nt.assert_in('line1\n', s)
861 nt.assert_in('line1\n', s)
860 nt.assert_in('line2', s)
862 nt.assert_in('line2', s)
861
863
862 @dec.skip_win32
864 @dec.skip_win32
863 def test_file_double_quote():
865 def test_file_double_quote():
864 """Basic %%writefile with embedded double quotes"""
866 """Basic %%writefile with embedded double quotes"""
865 ip = get_ipython()
867 ip = get_ipython()
866 with TemporaryDirectory() as td:
868 with TemporaryDirectory() as td:
867 fname = os.path.join(td, '"file1"')
869 fname = os.path.join(td, '"file1"')
868 ip.run_cell_magic("writefile", fname, u'\n'.join([
870 ip.run_cell_magic("writefile", fname, u'\n'.join([
869 'line1',
871 'line1',
870 'line2',
872 'line2',
871 ]))
873 ]))
872 with open(fname) as f:
874 with open(fname) as f:
873 s = f.read()
875 s = f.read()
874 nt.assert_in('line1\n', s)
876 nt.assert_in('line1\n', s)
875 nt.assert_in('line2', s)
877 nt.assert_in('line2', s)
876
878
877 def test_file_var_expand():
879 def test_file_var_expand():
878 """%%writefile $filename"""
880 """%%writefile $filename"""
879 ip = get_ipython()
881 ip = get_ipython()
880 with TemporaryDirectory() as td:
882 with TemporaryDirectory() as td:
881 fname = os.path.join(td, 'file1')
883 fname = os.path.join(td, 'file1')
882 ip.user_ns['filename'] = fname
884 ip.user_ns['filename'] = fname
883 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
885 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
884 'line1',
886 'line1',
885 'line2',
887 'line2',
886 ]))
888 ]))
887 with open(fname) as f:
889 with open(fname) as f:
888 s = f.read()
890 s = f.read()
889 nt.assert_in('line1\n', s)
891 nt.assert_in('line1\n', s)
890 nt.assert_in('line2', s)
892 nt.assert_in('line2', s)
891
893
892 def test_file_unicode():
894 def test_file_unicode():
893 """%%writefile with unicode cell"""
895 """%%writefile with unicode cell"""
894 ip = get_ipython()
896 ip = get_ipython()
895 with TemporaryDirectory() as td:
897 with TemporaryDirectory() as td:
896 fname = os.path.join(td, 'file1')
898 fname = os.path.join(td, 'file1')
897 ip.run_cell_magic("writefile", fname, u'\n'.join([
899 ip.run_cell_magic("writefile", fname, u'\n'.join([
898 u'liné1',
900 u'liné1',
899 u'liné2',
901 u'liné2',
900 ]))
902 ]))
901 with io.open(fname, encoding='utf-8') as f:
903 with io.open(fname, encoding='utf-8') as f:
902 s = f.read()
904 s = f.read()
903 nt.assert_in(u'liné1\n', s)
905 nt.assert_in(u'liné1\n', s)
904 nt.assert_in(u'liné2', s)
906 nt.assert_in(u'liné2', s)
905
907
906 def test_file_amend():
908 def test_file_amend():
907 """%%writefile -a amends files"""
909 """%%writefile -a amends files"""
908 ip = get_ipython()
910 ip = get_ipython()
909 with TemporaryDirectory() as td:
911 with TemporaryDirectory() as td:
910 fname = os.path.join(td, 'file2')
912 fname = os.path.join(td, 'file2')
911 ip.run_cell_magic("writefile", fname, u'\n'.join([
913 ip.run_cell_magic("writefile", fname, u'\n'.join([
912 'line1',
914 'line1',
913 'line2',
915 'line2',
914 ]))
916 ]))
915 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
917 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
916 'line3',
918 'line3',
917 'line4',
919 'line4',
918 ]))
920 ]))
919 with open(fname) as f:
921 with open(fname) as f:
920 s = f.read()
922 s = f.read()
921 nt.assert_in('line1\n', s)
923 nt.assert_in('line1\n', s)
922 nt.assert_in('line3\n', s)
924 nt.assert_in('line3\n', s)
923
925
924 def test_file_spaces():
926 def test_file_spaces():
925 """%%file with spaces in filename"""
927 """%%file with spaces in filename"""
926 ip = get_ipython()
928 ip = get_ipython()
927 with TemporaryWorkingDirectory() as td:
929 with TemporaryWorkingDirectory() as td:
928 fname = "file name"
930 fname = "file name"
929 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
931 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
930 'line1',
932 'line1',
931 'line2',
933 'line2',
932 ]))
934 ]))
933 with open(fname) as f:
935 with open(fname) as f:
934 s = f.read()
936 s = f.read()
935 nt.assert_in('line1\n', s)
937 nt.assert_in('line1\n', s)
936 nt.assert_in('line2', s)
938 nt.assert_in('line2', s)
937
939
938 def test_script_config():
940 def test_script_config():
939 ip = get_ipython()
941 ip = get_ipython()
940 ip.config.ScriptMagics.script_magics = ['whoda']
942 ip.config.ScriptMagics.script_magics = ['whoda']
941 sm = script.ScriptMagics(shell=ip)
943 sm = script.ScriptMagics(shell=ip)
942 nt.assert_in('whoda', sm.magics['cell'])
944 nt.assert_in('whoda', sm.magics['cell'])
943
945
944 @dec.skip_win32
946 @dec.skip_win32
945 def test_script_out():
947 def test_script_out():
946 ip = get_ipython()
948 ip = get_ipython()
947 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
949 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
948 nt.assert_equal(ip.user_ns['output'], 'hi\n')
950 nt.assert_equal(ip.user_ns['output'], 'hi\n')
949
951
950 @dec.skip_win32
952 @dec.skip_win32
951 def test_script_err():
953 def test_script_err():
952 ip = get_ipython()
954 ip = get_ipython()
953 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
955 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
954 nt.assert_equal(ip.user_ns['error'], 'hello\n')
956 nt.assert_equal(ip.user_ns['error'], 'hello\n')
955
957
956 @dec.skip_win32
958 @dec.skip_win32
957 def test_script_out_err():
959 def test_script_out_err():
958 ip = get_ipython()
960 ip = get_ipython()
959 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
961 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
960 nt.assert_equal(ip.user_ns['output'], 'hi\n')
962 nt.assert_equal(ip.user_ns['output'], 'hi\n')
961 nt.assert_equal(ip.user_ns['error'], 'hello\n')
963 nt.assert_equal(ip.user_ns['error'], 'hello\n')
962
964
963 @dec.skip_win32
965 @dec.skip_win32
964 def test_script_bg_out():
966 def test_script_bg_out():
965 ip = get_ipython()
967 ip = get_ipython()
966 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
968 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
967
969
968 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
970 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
969 ip.user_ns['output'].close()
971 ip.user_ns['output'].close()
970
972
971 @dec.skip_win32
973 @dec.skip_win32
972 def test_script_bg_err():
974 def test_script_bg_err():
973 ip = get_ipython()
975 ip = get_ipython()
974 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
976 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
975 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
977 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
976 ip.user_ns['error'].close()
978 ip.user_ns['error'].close()
977
979
978 @dec.skip_win32
980 @dec.skip_win32
979 def test_script_bg_out_err():
981 def test_script_bg_out_err():
980 ip = get_ipython()
982 ip = get_ipython()
981 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
983 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
982 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
984 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
983 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
985 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
984 ip.user_ns['output'].close()
986 ip.user_ns['output'].close()
985 ip.user_ns['error'].close()
987 ip.user_ns['error'].close()
986
988
987 def test_script_defaults():
989 def test_script_defaults():
988 ip = get_ipython()
990 ip = get_ipython()
989 for cmd in ['sh', 'bash', 'perl', 'ruby']:
991 for cmd in ['sh', 'bash', 'perl', 'ruby']:
990 try:
992 try:
991 find_cmd(cmd)
993 find_cmd(cmd)
992 except Exception:
994 except Exception:
993 pass
995 pass
994 else:
996 else:
995 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
997 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
996
998
997
999
998 @magics_class
1000 @magics_class
999 class FooFoo(Magics):
1001 class FooFoo(Magics):
1000 """class with both %foo and %%foo magics"""
1002 """class with both %foo and %%foo magics"""
1001 @line_magic('foo')
1003 @line_magic('foo')
1002 def line_foo(self, line):
1004 def line_foo(self, line):
1003 "I am line foo"
1005 "I am line foo"
1004 pass
1006 pass
1005
1007
1006 @cell_magic("foo")
1008 @cell_magic("foo")
1007 def cell_foo(self, line, cell):
1009 def cell_foo(self, line, cell):
1008 "I am cell foo, not line foo"
1010 "I am cell foo, not line foo"
1009 pass
1011 pass
1010
1012
1011 def test_line_cell_info():
1013 def test_line_cell_info():
1012 """%%foo and %foo magics are distinguishable to inspect"""
1014 """%%foo and %foo magics are distinguishable to inspect"""
1013 ip = get_ipython()
1015 ip = get_ipython()
1014 ip.magics_manager.register(FooFoo)
1016 ip.magics_manager.register(FooFoo)
1015 oinfo = ip.object_inspect('foo')
1017 oinfo = ip.object_inspect('foo')
1016 nt.assert_true(oinfo['found'])
1018 nt.assert_true(oinfo['found'])
1017 nt.assert_true(oinfo['ismagic'])
1019 nt.assert_true(oinfo['ismagic'])
1018
1020
1019 oinfo = ip.object_inspect('%%foo')
1021 oinfo = ip.object_inspect('%%foo')
1020 nt.assert_true(oinfo['found'])
1022 nt.assert_true(oinfo['found'])
1021 nt.assert_true(oinfo['ismagic'])
1023 nt.assert_true(oinfo['ismagic'])
1022 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1024 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1023
1025
1024 oinfo = ip.object_inspect('%foo')
1026 oinfo = ip.object_inspect('%foo')
1025 nt.assert_true(oinfo['found'])
1027 nt.assert_true(oinfo['found'])
1026 nt.assert_true(oinfo['ismagic'])
1028 nt.assert_true(oinfo['ismagic'])
1027 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1029 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1028
1030
1029 def test_multiple_magics():
1031 def test_multiple_magics():
1030 ip = get_ipython()
1032 ip = get_ipython()
1031 foo1 = FooFoo(ip)
1033 foo1 = FooFoo(ip)
1032 foo2 = FooFoo(ip)
1034 foo2 = FooFoo(ip)
1033 mm = ip.magics_manager
1035 mm = ip.magics_manager
1034 mm.register(foo1)
1036 mm.register(foo1)
1035 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
1037 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
1036 mm.register(foo2)
1038 mm.register(foo2)
1037 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
1039 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
1038
1040
1039 def test_alias_magic():
1041 def test_alias_magic():
1040 """Test %alias_magic."""
1042 """Test %alias_magic."""
1041 ip = get_ipython()
1043 ip = get_ipython()
1042 mm = ip.magics_manager
1044 mm = ip.magics_manager
1043
1045
1044 # Basic operation: both cell and line magics are created, if possible.
1046 # Basic operation: both cell and line magics are created, if possible.
1045 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1047 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1046 nt.assert_in('timeit_alias', mm.magics['line'])
1048 nt.assert_in('timeit_alias', mm.magics['line'])
1047 nt.assert_in('timeit_alias', mm.magics['cell'])
1049 nt.assert_in('timeit_alias', mm.magics['cell'])
1048
1050
1049 # --cell is specified, line magic not created.
1051 # --cell is specified, line magic not created.
1050 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1052 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1051 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1053 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1052 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1054 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1053
1055
1054 # Test that line alias is created successfully.
1056 # Test that line alias is created successfully.
1055 ip.run_line_magic('alias_magic', '--line env_alias env')
1057 ip.run_line_magic('alias_magic', '--line env_alias env')
1056 nt.assert_equal(ip.run_line_magic('env', ''),
1058 nt.assert_equal(ip.run_line_magic('env', ''),
1057 ip.run_line_magic('env_alias', ''))
1059 ip.run_line_magic('env_alias', ''))
1058
1060
1059 # Test that line alias with parameters passed in is created successfully.
1061 # Test that line alias with parameters passed in is created successfully.
1060 ip.run_line_magic('alias_magic', '--line history_alias history --params ' + shlex.quote('3'))
1062 ip.run_line_magic('alias_magic', '--line history_alias history --params ' + shlex.quote('3'))
1061 nt.assert_in('history_alias', mm.magics['line'])
1063 nt.assert_in('history_alias', mm.magics['line'])
1062
1064
1063
1065
1064 def test_save():
1066 def test_save():
1065 """Test %save."""
1067 """Test %save."""
1066 ip = get_ipython()
1068 ip = get_ipython()
1067 ip.history_manager.reset() # Clear any existing history.
1069 ip.history_manager.reset() # Clear any existing history.
1068 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
1070 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
1069 for i, cmd in enumerate(cmds, start=1):
1071 for i, cmd in enumerate(cmds, start=1):
1070 ip.history_manager.store_inputs(i, cmd)
1072 ip.history_manager.store_inputs(i, cmd)
1071 with TemporaryDirectory() as tmpdir:
1073 with TemporaryDirectory() as tmpdir:
1072 file = os.path.join(tmpdir, "testsave.py")
1074 file = os.path.join(tmpdir, "testsave.py")
1073 ip.run_line_magic("save", "%s 1-10" % file)
1075 ip.run_line_magic("save", "%s 1-10" % file)
1074 with open(file) as f:
1076 with open(file) as f:
1075 content = f.read()
1077 content = f.read()
1076 nt.assert_equal(content.count(cmds[0]), 1)
1078 nt.assert_equal(content.count(cmds[0]), 1)
1077 nt.assert_in('coding: utf-8', content)
1079 nt.assert_in('coding: utf-8', content)
1078 ip.run_line_magic("save", "-a %s 1-10" % file)
1080 ip.run_line_magic("save", "-a %s 1-10" % file)
1079 with open(file) as f:
1081 with open(file) as f:
1080 content = f.read()
1082 content = f.read()
1081 nt.assert_equal(content.count(cmds[0]), 2)
1083 nt.assert_equal(content.count(cmds[0]), 2)
1082 nt.assert_in('coding: utf-8', content)
1084 nt.assert_in('coding: utf-8', content)
1083
1085
1084
1086
1085 def test_store():
1087 def test_store():
1086 """Test %store."""
1088 """Test %store."""
1087 ip = get_ipython()
1089 ip = get_ipython()
1088 ip.run_line_magic('load_ext', 'storemagic')
1090 ip.run_line_magic('load_ext', 'storemagic')
1089
1091
1090 # make sure the storage is empty
1092 # make sure the storage is empty
1091 ip.run_line_magic('store', '-z')
1093 ip.run_line_magic('store', '-z')
1092 ip.user_ns['var'] = 42
1094 ip.user_ns['var'] = 42
1093 ip.run_line_magic('store', 'var')
1095 ip.run_line_magic('store', 'var')
1094 ip.user_ns['var'] = 39
1096 ip.user_ns['var'] = 39
1095 ip.run_line_magic('store', '-r')
1097 ip.run_line_magic('store', '-r')
1096 nt.assert_equal(ip.user_ns['var'], 42)
1098 nt.assert_equal(ip.user_ns['var'], 42)
1097
1099
1098 ip.run_line_magic('store', '-d var')
1100 ip.run_line_magic('store', '-d var')
1099 ip.user_ns['var'] = 39
1101 ip.user_ns['var'] = 39
1100 ip.run_line_magic('store' , '-r')
1102 ip.run_line_magic('store' , '-r')
1101 nt.assert_equal(ip.user_ns['var'], 39)
1103 nt.assert_equal(ip.user_ns['var'], 39)
1102
1104
1103
1105
1104 def _run_edit_test(arg_s, exp_filename=None,
1106 def _run_edit_test(arg_s, exp_filename=None,
1105 exp_lineno=-1,
1107 exp_lineno=-1,
1106 exp_contents=None,
1108 exp_contents=None,
1107 exp_is_temp=None):
1109 exp_is_temp=None):
1108 ip = get_ipython()
1110 ip = get_ipython()
1109 M = code.CodeMagics(ip)
1111 M = code.CodeMagics(ip)
1110 last_call = ['','']
1112 last_call = ['','']
1111 opts,args = M.parse_options(arg_s,'prxn:')
1113 opts,args = M.parse_options(arg_s,'prxn:')
1112 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1114 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1113
1115
1114 if exp_filename is not None:
1116 if exp_filename is not None:
1115 nt.assert_equal(exp_filename, filename)
1117 nt.assert_equal(exp_filename, filename)
1116 if exp_contents is not None:
1118 if exp_contents is not None:
1117 with io.open(filename, 'r', encoding='utf-8') as f:
1119 with io.open(filename, 'r', encoding='utf-8') as f:
1118 contents = f.read()
1120 contents = f.read()
1119 nt.assert_equal(exp_contents, contents)
1121 nt.assert_equal(exp_contents, contents)
1120 if exp_lineno != -1:
1122 if exp_lineno != -1:
1121 nt.assert_equal(exp_lineno, lineno)
1123 nt.assert_equal(exp_lineno, lineno)
1122 if exp_is_temp is not None:
1124 if exp_is_temp is not None:
1123 nt.assert_equal(exp_is_temp, is_temp)
1125 nt.assert_equal(exp_is_temp, is_temp)
1124
1126
1125
1127
1126 def test_edit_interactive():
1128 def test_edit_interactive():
1127 """%edit on interactively defined objects"""
1129 """%edit on interactively defined objects"""
1128 ip = get_ipython()
1130 ip = get_ipython()
1129 n = ip.execution_count
1131 n = ip.execution_count
1130 ip.run_cell(u"def foo(): return 1", store_history=True)
1132 ip.run_cell(u"def foo(): return 1", store_history=True)
1131
1133
1132 try:
1134 try:
1133 _run_edit_test("foo")
1135 _run_edit_test("foo")
1134 except code.InteractivelyDefined as e:
1136 except code.InteractivelyDefined as e:
1135 nt.assert_equal(e.index, n)
1137 nt.assert_equal(e.index, n)
1136 else:
1138 else:
1137 raise AssertionError("Should have raised InteractivelyDefined")
1139 raise AssertionError("Should have raised InteractivelyDefined")
1138
1140
1139
1141
1140 def test_edit_cell():
1142 def test_edit_cell():
1141 """%edit [cell id]"""
1143 """%edit [cell id]"""
1142 ip = get_ipython()
1144 ip = get_ipython()
1143
1145
1144 ip.run_cell(u"def foo(): return 1", store_history=True)
1146 ip.run_cell(u"def foo(): return 1", store_history=True)
1145
1147
1146 # test
1148 # test
1147 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1149 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1148
1150
1149 def test_bookmark():
1151 def test_bookmark():
1150 ip = get_ipython()
1152 ip = get_ipython()
1151 ip.run_line_magic('bookmark', 'bmname')
1153 ip.run_line_magic('bookmark', 'bmname')
1152 with tt.AssertPrints('bmname'):
1154 with tt.AssertPrints('bmname'):
1153 ip.run_line_magic('bookmark', '-l')
1155 ip.run_line_magic('bookmark', '-l')
1154 ip.run_line_magic('bookmark', '-d bmname')
1156 ip.run_line_magic('bookmark', '-d bmname')
1155
1157
1156 def test_ls_magic():
1158 def test_ls_magic():
1157 ip = get_ipython()
1159 ip = get_ipython()
1158 json_formatter = ip.display_formatter.formatters['application/json']
1160 json_formatter = ip.display_formatter.formatters['application/json']
1159 json_formatter.enabled = True
1161 json_formatter.enabled = True
1160 lsmagic = ip.magic('lsmagic')
1162 lsmagic = ip.magic('lsmagic')
1161 with warnings.catch_warnings(record=True) as w:
1163 with warnings.catch_warnings(record=True) as w:
1162 j = json_formatter(lsmagic)
1164 j = json_formatter(lsmagic)
1163 nt.assert_equal(sorted(j), ['cell', 'line'])
1165 nt.assert_equal(sorted(j), ['cell', 'line'])
1164 nt.assert_equal(w, []) # no warnings
1166 nt.assert_equal(w, []) # no warnings
1165
1167
1166 def test_strip_initial_indent():
1168 def test_strip_initial_indent():
1167 def sii(s):
1169 def sii(s):
1168 lines = s.splitlines()
1170 lines = s.splitlines()
1169 return '\n'.join(code.strip_initial_indent(lines))
1171 return '\n'.join(code.strip_initial_indent(lines))
1170
1172
1171 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1173 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1172 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1174 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1173 nt.assert_equal(sii("a\n b"), "a\n b")
1175 nt.assert_equal(sii("a\n b"), "a\n b")
1174
1176
1175 def test_logging_magic_quiet_from_arg():
1177 def test_logging_magic_quiet_from_arg():
1176 _ip.config.LoggingMagics.quiet = False
1178 _ip.config.LoggingMagics.quiet = False
1177 lm = logging.LoggingMagics(shell=_ip)
1179 lm = logging.LoggingMagics(shell=_ip)
1178 with TemporaryDirectory() as td:
1180 with TemporaryDirectory() as td:
1179 try:
1181 try:
1180 with tt.AssertNotPrints(re.compile("Activating.*")):
1182 with tt.AssertNotPrints(re.compile("Activating.*")):
1181 lm.logstart('-q {}'.format(
1183 lm.logstart('-q {}'.format(
1182 os.path.join(td, "quiet_from_arg.log")))
1184 os.path.join(td, "quiet_from_arg.log")))
1183 finally:
1185 finally:
1184 _ip.logger.logstop()
1186 _ip.logger.logstop()
1185
1187
1186 def test_logging_magic_quiet_from_config():
1188 def test_logging_magic_quiet_from_config():
1187 _ip.config.LoggingMagics.quiet = True
1189 _ip.config.LoggingMagics.quiet = True
1188 lm = logging.LoggingMagics(shell=_ip)
1190 lm = logging.LoggingMagics(shell=_ip)
1189 with TemporaryDirectory() as td:
1191 with TemporaryDirectory() as td:
1190 try:
1192 try:
1191 with tt.AssertNotPrints(re.compile("Activating.*")):
1193 with tt.AssertNotPrints(re.compile("Activating.*")):
1192 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1194 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1193 finally:
1195 finally:
1194 _ip.logger.logstop()
1196 _ip.logger.logstop()
1195
1197
1196
1198
1197 def test_logging_magic_not_quiet():
1199 def test_logging_magic_not_quiet():
1198 _ip.config.LoggingMagics.quiet = False
1200 _ip.config.LoggingMagics.quiet = False
1199 lm = logging.LoggingMagics(shell=_ip)
1201 lm = logging.LoggingMagics(shell=_ip)
1200 with TemporaryDirectory() as td:
1202 with TemporaryDirectory() as td:
1201 try:
1203 try:
1202 with tt.AssertPrints(re.compile("Activating.*")):
1204 with tt.AssertPrints(re.compile("Activating.*")):
1203 lm.logstart(os.path.join(td, "not_quiet.log"))
1205 lm.logstart(os.path.join(td, "not_quiet.log"))
1204 finally:
1206 finally:
1205 _ip.logger.logstop()
1207 _ip.logger.logstop()
1206
1208
1207
1209
1208 def test_time_no_var_expand():
1210 def test_time_no_var_expand():
1209 _ip.user_ns['a'] = 5
1211 _ip.user_ns['a'] = 5
1210 _ip.user_ns['b'] = []
1212 _ip.user_ns['b'] = []
1211 _ip.magic('time b.append("{a}")')
1213 _ip.magic('time b.append("{a}")')
1212 assert _ip.user_ns['b'] == ['{a}']
1214 assert _ip.user_ns['b'] == ['{a}']
1213
1215
1214
1216
1215 # this is slow, put at the end for local testing.
1217 # this is slow, put at the end for local testing.
1216 def test_timeit_arguments():
1218 def test_timeit_arguments():
1217 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1219 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1218 if sys.version_info < (3,7):
1220 if sys.version_info < (3,7):
1219 _ip.magic("timeit -n1 -r1 ('#')")
1221 _ip.magic("timeit -n1 -r1 ('#')")
1220 else:
1222 else:
1221 # 3.7 optimize no-op statement like above out, and complain there is
1223 # 3.7 optimize no-op statement like above out, and complain there is
1222 # nothing in the for loop.
1224 # nothing in the for loop.
1223 _ip.magic("timeit -n1 -r1 a=('#')")
1225 _ip.magic("timeit -n1 -r1 a=('#')")
@@ -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