##// END OF EJS Templates
Merge pull request #4151 from takluyver/drop-alias...
Thomas Kluyver -
r12759:b1100aa2 merge
parent child Browse files
Show More
@@ -0,0 +1,41 b''
1 from IPython.utils.capture import capture_output
2
3 import nose.tools as nt
4
5 def test_alias_lifecycle():
6 name = 'test_alias1'
7 cmd = 'echo "Hello"'
8 am = _ip.alias_manager
9 am.clear_aliases()
10 am.define_alias(name, cmd)
11 assert am.is_alias(name)
12 nt.assert_equal(am.retrieve_alias(name), cmd)
13 nt.assert_in((name, cmd), am.aliases)
14
15 # Test running the alias
16 orig_system = _ip.system
17 result = []
18 _ip.system = result.append
19 try:
20 _ip.run_cell('%{}'.format(name))
21 result = [c.strip() for c in result]
22 nt.assert_equal(result, [cmd])
23 finally:
24 _ip.system = orig_system
25
26 # Test removing the alias
27 am.undefine_alias(name)
28 assert not am.is_alias(name)
29 with nt.assert_raises(ValueError):
30 am.retrieve_alias(name)
31 nt.assert_not_in((name, cmd), am.aliases)
32
33
34 def test_alias_args_error():
35 """Error expanding with wrong number of arguments"""
36 _ip.alias_manager.define_alias('parts', 'echo first %s second %s')
37 # capture stderr:
38 with capture_output() as cap:
39 _ip.run_cell('parts 1')
40
41 nt.assert_equal(cap.stderr.split(':')[0], 'UsageError') No newline at end of file
@@ -0,0 +1,3 b''
1 - The alias system has been reimplemented to use magic functions. There should be little
2 visible difference while automagics are enabled, as they are by default, but parts of the
3 :class:`~IPython.core.alias.AliasManager` API have been removed.
@@ -20,17 +20,15 b' Authors:'
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import __builtin__
24 import keyword
25 import os
23 import os
26 import re
24 import re
27 import sys
25 import sys
28
26
29 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
30 from IPython.core.splitinput import split_user_input
28 from IPython.core.error import UsageError
31
29
32 from IPython.utils.traitlets import List, Instance
30 from IPython.utils.traitlets import List, Instance
33 from IPython.utils.warn import warn, error
31 from IPython.utils.warn import error
34
32
35 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
36 # Utilities
34 # Utilities
@@ -104,6 +102,70 b' class AliasError(Exception):'
104 class InvalidAliasError(AliasError):
102 class InvalidAliasError(AliasError):
105 pass
103 pass
106
104
105 class Alias(object):
106 """Callable object storing the details of one alias.
107
108 Instances are registered as magic functions to allow use of aliases.
109 """
110
111 # Prepare blacklist
112 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
113
114 def __init__(self, shell, name, cmd):
115 self.shell = shell
116 self.name = name
117 self.cmd = cmd
118 self.nargs = self.validate()
119
120 def validate(self):
121 """Validate the alias, and return the number of arguments."""
122 if self.name in self.blacklist:
123 raise InvalidAliasError("The name %s can't be aliased "
124 "because it is a keyword or builtin." % self.name)
125 try:
126 caller = self.shell.magics_manager.magics['line'][self.name]
127 except KeyError:
128 pass
129 else:
130 if not isinstance(caller, Alias):
131 raise InvalidAliasError("The name %s can't be aliased "
132 "because it is another magic command." % self.name)
133
134 if not (isinstance(self.cmd, basestring)):
135 raise InvalidAliasError("An alias command must be a string, "
136 "got: %r" % self.cmd)
137
138 nargs = self.cmd.count('%s')
139
140 if (nargs > 0) and (self.cmd.find('%l') >= 0):
141 raise InvalidAliasError('The %s and %l specifiers are mutually '
142 'exclusive in alias definitions.')
143
144 return nargs
145
146 def __repr__(self):
147 return "<alias {} for {!r}>".format(self.name, self.cmd)
148
149 def __call__(self, rest=''):
150 cmd = self.cmd
151 nargs = self.nargs
152 # Expand the %l special to be the user's input line
153 if cmd.find('%l') >= 0:
154 cmd = cmd.replace('%l', rest)
155 rest = ''
156 if nargs==0:
157 # Simple, argument-less aliases
158 cmd = '%s %s' % (cmd, rest)
159 else:
160 # Handle aliases with positional arguments
161 args = rest.split(None, nargs)
162 if len(args) < nargs:
163 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
164 (self.name, nargs, len(args)))
165 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
166
167 self.shell.system(cmd)
168
107 #-----------------------------------------------------------------------------
169 #-----------------------------------------------------------------------------
108 # Main AliasManager class
170 # Main AliasManager class
109 #-----------------------------------------------------------------------------
171 #-----------------------------------------------------------------------------
@@ -116,35 +178,19 b' class AliasManager(Configurable):'
116
178
117 def __init__(self, shell=None, **kwargs):
179 def __init__(self, shell=None, **kwargs):
118 super(AliasManager, self).__init__(shell=shell, **kwargs)
180 super(AliasManager, self).__init__(shell=shell, **kwargs)
119 self.alias_table = {}
181 # For convenient access
120 self.exclude_aliases()
182 self.linemagics = self.shell.magics_manager.magics['line']
121 self.init_aliases()
183 self.init_aliases()
122
184
123 def __contains__(self, name):
124 return name in self.alias_table
125
126 @property
127 def aliases(self):
128 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
129
130 def exclude_aliases(self):
131 # set of things NOT to alias (keywords, builtins and some magics)
132 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
133 no_alias.update(set(keyword.kwlist))
134 no_alias.update(set(__builtin__.__dict__.keys()))
135 self.no_alias = no_alias
136
137 def init_aliases(self):
185 def init_aliases(self):
138 # Load default aliases
186 # Load default & user aliases
139 for name, cmd in self.default_aliases:
187 for name, cmd in self.default_aliases + self.user_aliases:
140 self.soft_define_alias(name, cmd)
141
142 # Load user aliases
143 for name, cmd in self.user_aliases:
144 self.soft_define_alias(name, cmd)
188 self.soft_define_alias(name, cmd)
145
189
146 def clear_aliases(self):
190 @property
147 self.alias_table.clear()
191 def aliases(self):
192 return [(n, func.cmd) for (n, func) in self.linemagics.items()
193 if isinstance(func, Alias)]
148
194
149 def soft_define_alias(self, name, cmd):
195 def soft_define_alias(self, name, cmd):
150 """Define an alias, but don't raise on an AliasError."""
196 """Define an alias, but don't raise on an AliasError."""
@@ -159,104 +205,33 b' class AliasManager(Configurable):'
159 This will raise an :exc:`AliasError` if there are validation
205 This will raise an :exc:`AliasError` if there are validation
160 problems.
206 problems.
161 """
207 """
162 nargs = self.validate_alias(name, cmd)
208 caller = Alias(shell=self.shell, name=name, cmd=cmd)
163 self.alias_table[name] = (nargs, cmd)
209 self.shell.magics_manager.register_function(caller, magic_kind='line',
210 magic_name=name)
164
211
165 def undefine_alias(self, name):
212 def get_alias(self, name):
166 if name in self.alias_table:
213 """Return an alias, or None if no alias by that name exists."""
167 del self.alias_table[name]
214 aname = self.linemagics.get(name, None)
215 return aname if isinstance(aname, Alias) else None
168
216
169 def validate_alias(self, name, cmd):
217 def is_alias(self, name):
170 """Validate an alias and return the its number of arguments."""
218 """Return whether or not a given name has been defined as an alias"""
171 if name in self.no_alias:
219 return self.get_alias(name) is not None
172 raise InvalidAliasError("The name %s can't be aliased "
173 "because it is a keyword or builtin." % name)
174 if not (isinstance(cmd, basestring)):
175 raise InvalidAliasError("An alias command must be a string, "
176 "got: %r" % cmd)
177 nargs = cmd.count('%s')
178 if nargs>0 and cmd.find('%l')>=0:
179 raise InvalidAliasError('The %s and %l specifiers are mutually '
180 'exclusive in alias definitions.')
181 return nargs
182
220
183 def call_alias(self, alias, rest=''):
221 def undefine_alias(self, name):
184 """Call an alias given its name and the rest of the line."""
222 if self.is_alias(name):
185 cmd = self.transform_alias(alias, rest)
223 del self.linemagics[name]
186 try:
187 self.shell.system(cmd)
188 except:
189 self.shell.showtraceback()
190
191 def transform_alias(self, alias,rest=''):
192 """Transform alias to system command string."""
193 nargs, cmd = self.alias_table[alias]
194
195 if ' ' in cmd and os.path.isfile(cmd):
196 cmd = '"%s"' % cmd
197
198 # Expand the %l special to be the user's input line
199 if cmd.find('%l') >= 0:
200 cmd = cmd.replace('%l', rest)
201 rest = ''
202 if nargs==0:
203 # Simple, argument-less aliases
204 cmd = '%s %s' % (cmd, rest)
205 else:
224 else:
206 # Handle aliases with positional arguments
225 raise ValueError('%s is not an alias' % name)
207 args = rest.split(None, nargs)
208 if len(args) < nargs:
209 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
210 (alias, nargs, len(args)))
211 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
212 return cmd
213
214 def expand_alias(self, line):
215 """ Expand an alias in the command line
216
226
217 Returns the provided command line, possibly with the first word
227 def clear_aliases(self):
218 (command) translated according to alias expansion rules.
228 for name, cmd in self.aliases:
219
229 self.undefine_alias(name)
220 [ipython]|16> _ip.expand_aliases("np myfile.txt")
230
221 <16> 'q:/opt/np/notepad++.exe myfile.txt'
231 def retrieve_alias(self, name):
222 """
232 """Retrieve the command to which an alias expands."""
223
233 caller = self.get_alias(name)
224 pre,_,fn,rest = split_user_input(line)
234 if caller:
225 res = pre + self.expand_aliases(fn, rest)
235 return caller.cmd
226 return res
236 else:
227
237 raise ValueError('%s is not an alias' % name)
228 def expand_aliases(self, fn, rest):
229 """Expand multiple levels of aliases:
230
231 if:
232
233 alias foo bar /tmp
234 alias baz foo
235
236 then:
237
238 baz huhhahhei -> bar /tmp huhhahhei
239 """
240 line = fn + " " + rest
241
242 done = set()
243 while 1:
244 pre,_,fn,rest = split_user_input(line, shell_line_split)
245 if fn in self.alias_table:
246 if fn in done:
247 warn("Cyclic alias definition, repeated '%s'" % fn)
248 return ""
249 done.add(fn)
250
251 l2 = self.transform_alias(fn, rest)
252 if l2 == line:
253 break
254 # ls -> ls -F should not recurse forever
255 if l2.split(None,1)[0] == line.split(None,1)[0]:
256 line = l2
257 break
258 line = l2
259 else:
260 break
261
262 return line
@@ -431,8 +431,7 b' class IPCompleter(Completer):'
431 )
431 )
432
432
433 def __init__(self, shell=None, namespace=None, global_namespace=None,
433 def __init__(self, shell=None, namespace=None, global_namespace=None,
434 alias_table=None, use_readline=True,
434 use_readline=True, config=None, **kwargs):
435 config=None, **kwargs):
436 """IPCompleter() -> completer
435 """IPCompleter() -> completer
437
436
438 Return a completer object suitable for use by the readline library
437 Return a completer object suitable for use by the readline library
@@ -450,9 +449,6 b' class IPCompleter(Completer):'
450 handle cases (such as IPython embedded inside functions) where
449 handle cases (such as IPython embedded inside functions) where
451 both Python scopes are visible.
450 both Python scopes are visible.
452
451
453 - If alias_table is supplied, it should be a dictionary of aliases
454 to complete.
455
456 use_readline : bool, optional
452 use_readline : bool, optional
457 If true, use the readline library. This completer can still function
453 If true, use the readline library. This completer can still function
458 without readline, though in that case callers must provide some extra
454 without readline, though in that case callers must provide some extra
@@ -476,9 +472,6 b' class IPCompleter(Completer):'
476 # List where completion matches will be stored
472 # List where completion matches will be stored
477 self.matches = []
473 self.matches = []
478 self.shell = shell
474 self.shell = shell
479 if alias_table is None:
480 alias_table = {}
481 self.alias_table = alias_table
482 # Regexp to split filenames with spaces in them
475 # Regexp to split filenames with spaces in them
483 self.space_name_re = re.compile(r'([^\\] )')
476 self.space_name_re = re.compile(r'([^\\] )')
484 # Hold a local ref. to glob.glob for speed
477 # Hold a local ref. to glob.glob for speed
@@ -505,7 +498,6 b' class IPCompleter(Completer):'
505 self.matchers = [self.python_matches,
498 self.matchers = [self.python_matches,
506 self.file_matches,
499 self.file_matches,
507 self.magic_matches,
500 self.magic_matches,
508 self.alias_matches,
509 self.python_func_kw_matches,
501 self.python_func_kw_matches,
510 ]
502 ]
511
503
@@ -628,22 +620,6 b' class IPCompleter(Completer):'
628 comp += [ pre+m for m in line_magics if m.startswith(bare_text)]
620 comp += [ pre+m for m in line_magics if m.startswith(bare_text)]
629 return comp
621 return comp
630
622
631 def alias_matches(self, text):
632 """Match internal system aliases"""
633 #print 'Completer->alias_matches:',text,'lb',self.text_until_cursor # dbg
634
635 # if we are not in the first 'item', alias matching
636 # doesn't make sense - unless we are starting with 'sudo' command.
637 main_text = self.text_until_cursor.lstrip()
638 if ' ' in main_text and not main_text.startswith('sudo'):
639 return []
640 text = os.path.expanduser(text)
641 aliases = self.alias_table.keys()
642 if text == '':
643 return aliases
644 else:
645 return [a for a in aliases if a.startswith(text)]
646
647 def python_matches(self,text):
623 def python_matches(self,text):
648 """Match attributes or global python names"""
624 """Match attributes or global python names"""
649
625
@@ -470,7 +470,6 b' class InteractiveShell(SingletonConfigurable):'
470 # because it and init_io have to come after init_readline.
470 # because it and init_io have to come after init_readline.
471 self.init_user_ns()
471 self.init_user_ns()
472 self.init_logger()
472 self.init_logger()
473 self.init_alias()
474 self.init_builtins()
473 self.init_builtins()
475
474
476 # The following was in post_config_initialization
475 # The following was in post_config_initialization
@@ -502,6 +501,7 b' class InteractiveShell(SingletonConfigurable):'
502 self.init_displayhook()
501 self.init_displayhook()
503 self.init_latextool()
502 self.init_latextool()
504 self.init_magics()
503 self.init_magics()
504 self.init_alias()
505 self.init_logstart()
505 self.init_logstart()
506 self.init_pdb()
506 self.init_pdb()
507 self.init_extension_manager()
507 self.init_extension_manager()
@@ -1363,9 +1363,7 b' class InteractiveShell(SingletonConfigurable):'
1363 namespaces = [ ('Interactive', self.user_ns),
1363 namespaces = [ ('Interactive', self.user_ns),
1364 ('Interactive (global)', self.user_global_ns),
1364 ('Interactive (global)', self.user_global_ns),
1365 ('Python builtin', builtin_mod.__dict__),
1365 ('Python builtin', builtin_mod.__dict__),
1366 ('Alias', self.alias_manager.alias_table),
1367 ]
1366 ]
1368 alias_ns = self.alias_manager.alias_table
1369
1367
1370 # initialize results to 'null'
1368 # initialize results to 'null'
1371 found = False; obj = None; ospace = None; ds = None;
1369 found = False; obj = None; ospace = None; ds = None;
@@ -1404,8 +1402,6 b' class InteractiveShell(SingletonConfigurable):'
1404 # If we finish the for loop (no break), we got all members
1402 # If we finish the for loop (no break), we got all members
1405 found = True
1403 found = True
1406 ospace = nsname
1404 ospace = nsname
1407 if ns == alias_ns:
1408 isalias = True
1409 break # namespace loop
1405 break # namespace loop
1410
1406
1411 # Try to see if it's magic
1407 # Try to see if it's magic
@@ -1940,7 +1936,6 b' class InteractiveShell(SingletonConfigurable):'
1940 self.Completer = IPCompleter(shell=self,
1936 self.Completer = IPCompleter(shell=self,
1941 namespace=self.user_ns,
1937 namespace=self.user_ns,
1942 global_namespace=self.user_global_ns,
1938 global_namespace=self.user_global_ns,
1943 alias_table=self.alias_manager.alias_table,
1944 use_readline=self.has_readline,
1939 use_readline=self.has_readline,
1945 parent=self,
1940 parent=self,
1946 )
1941 )
@@ -2305,7 +2300,6 b' class InteractiveShell(SingletonConfigurable):'
2305 def init_alias(self):
2300 def init_alias(self):
2306 self.alias_manager = AliasManager(shell=self, parent=self)
2301 self.alias_manager = AliasManager(shell=self, parent=self)
2307 self.configurables.append(self.alias_manager)
2302 self.configurables.append(self.alias_manager)
2308 self.ns_table['alias'] = self.alias_manager.alias_table,
2309
2303
2310 #-------------------------------------------------------------------------
2304 #-------------------------------------------------------------------------
2311 # Things related to extensions
2305 # Things related to extensions
@@ -26,6 +26,7 b' from pprint import pformat'
26 from IPython.core import magic_arguments
26 from IPython.core import magic_arguments
27 from IPython.core import oinspect
27 from IPython.core import oinspect
28 from IPython.core import page
28 from IPython.core import page
29 from IPython.core.alias import AliasError, Alias
29 from IPython.core.error import UsageError
30 from IPython.core.error import UsageError
30 from IPython.core.magic import (
31 from IPython.core.magic import (
31 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
32 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
@@ -113,10 +114,14 b' class OSMagics(Magics):'
113 # Now try to define a new one
114 # Now try to define a new one
114 try:
115 try:
115 alias,cmd = par.split(None, 1)
116 alias,cmd = par.split(None, 1)
116 except:
117 except TypeError:
117 print oinspect.getdoc(self.alias)
118 print(oinspect.getdoc(self.alias))
118 else:
119 return
119 self.shell.alias_manager.soft_define_alias(alias, cmd)
120
121 try:
122 self.shell.alias_manager.define_alias(alias, cmd)
123 except AliasError as e:
124 print(e)
120 # end magic_alias
125 # end magic_alias
121
126
122 @line_magic
127 @line_magic
@@ -124,7 +129,12 b' class OSMagics(Magics):'
124 """Remove an alias"""
129 """Remove an alias"""
125
130
126 aname = parameter_s.strip()
131 aname = parameter_s.strip()
127 self.shell.alias_manager.undefine_alias(aname)
132 try:
133 self.shell.alias_manager.undefine_alias(aname)
134 except ValueError as e:
135 print(e)
136 return
137
128 stored = self.shell.db.get('stored_aliases', {} )
138 stored = self.shell.db.get('stored_aliases', {} )
129 if aname in stored:
139 if aname in stored:
130 print "Removing %stored alias",aname
140 print "Removing %stored alias",aname
@@ -182,7 +192,7 b' class OSMagics(Magics):'
182 try:
192 try:
183 # Removes dots from the name since ipython
193 # Removes dots from the name since ipython
184 # will assume names with dots to be python.
194 # will assume names with dots to be python.
185 if ff not in self.shell.alias_manager:
195 if not self.shell.alias_manager.is_alias(ff):
186 self.shell.alias_manager.define_alias(
196 self.shell.alias_manager.define_alias(
187 ff.replace('.',''), ff)
197 ff.replace('.',''), ff)
188 except InvalidAliasError:
198 except InvalidAliasError:
@@ -190,7 +200,7 b' class OSMagics(Magics):'
190 else:
200 else:
191 syscmdlist.append(ff)
201 syscmdlist.append(ff)
192 else:
202 else:
193 no_alias = self.shell.alias_manager.no_alias
203 no_alias = Alias.blacklist
194 for pdir in path:
204 for pdir in path:
195 os.chdir(pdir)
205 os.chdir(pdir)
196 for ff in os.listdir(pdir):
206 for ff in os.listdir(pdir):
@@ -488,22 +488,6 b' class AutoMagicChecker(PrefilterChecker):'
488 return self.prefilter_manager.get_handler_by_name('magic')
488 return self.prefilter_manager.get_handler_by_name('magic')
489
489
490
490
491 class AliasChecker(PrefilterChecker):
492
493 priority = Integer(800, config=True)
494
495 def check(self, line_info):
496 "Check if the initital identifier on the line is an alias."
497 # Note: aliases can not contain '.'
498 head = line_info.ifun.split('.',1)[0]
499 if line_info.ifun not in self.shell.alias_manager \
500 or head not in self.shell.alias_manager \
501 or is_shadowed(head, self.shell):
502 return None
503
504 return self.prefilter_manager.get_handler_by_name('alias')
505
506
507 class PythonOpsChecker(PrefilterChecker):
491 class PythonOpsChecker(PrefilterChecker):
508
492
509 priority = Integer(900, config=True)
493 priority = Integer(900, config=True)
@@ -591,20 +575,6 b' class PrefilterHandler(Configurable):'
591 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
575 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
592
576
593
577
594 class AliasHandler(PrefilterHandler):
595
596 handler_name = Unicode('alias')
597
598 def handle(self, line_info):
599 """Handle alias input lines. """
600 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
601 # pre is needed, because it carries the leading whitespace. Otherwise
602 # aliases won't work in indented sections.
603 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
604
605 return line_out
606
607
608 class MacroHandler(PrefilterHandler):
578 class MacroHandler(PrefilterHandler):
609 handler_name = Unicode("macro")
579 handler_name = Unicode("macro")
610
580
@@ -730,14 +700,12 b' _default_checkers = ['
730 IPyAutocallChecker,
700 IPyAutocallChecker,
731 AssignmentChecker,
701 AssignmentChecker,
732 AutoMagicChecker,
702 AutoMagicChecker,
733 AliasChecker,
734 PythonOpsChecker,
703 PythonOpsChecker,
735 AutocallChecker
704 AutocallChecker
736 ]
705 ]
737
706
738 _default_handlers = [
707 _default_handlers = [
739 PrefilterHandler,
708 PrefilterHandler,
740 AliasHandler,
741 MacroHandler,
709 MacroHandler,
742 MagicHandler,
710 MagicHandler,
743 AutoHandler,
711 AutoHandler,
@@ -45,28 +45,6 b' def run(tests):'
45
45
46
46
47 def test_handlers():
47 def test_handlers():
48 # alias expansion
49
50 # We're using 'true' as our syscall of choice because it doesn't
51 # write anything to stdout.
52
53 # Turn off actual execution of aliases, because it's noisy
54 old_system_cmd = ip.system
55 ip.system = lambda cmd: None
56
57
58 ip.alias_manager.alias_table['an_alias'] = (0, 'true')
59 # These are useful for checking a particular recursive alias issue
60 ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top')
61 ip.alias_manager.alias_table['d'] = (0, 'true')
62 run([(i,py3compat.u_format(o)) for i,o in \
63 [("an_alias", "get_ipython().system({u}'true ')"), # alias
64 # Below: recursive aliases should expand whitespace-surrounded
65 # chars, *not* initial chars which happen to be aliases:
66 ("top", "get_ipython().system({u}'d:/cygwin/top ')"),
67 ]])
68 ip.system = old_system_cmd
69
70 call_idx = CallableIndexable()
48 call_idx = CallableIndexable()
71 ip.user_ns['call_idx'] = call_idx
49 ip.user_ns['call_idx'] = call_idx
72
50
@@ -106,17 +106,6 b' class InteractiveShellTestCase(unittest.TestCase):'
106 ip.run_cell('a = """\n%exit\n"""')
106 ip.run_cell('a = """\n%exit\n"""')
107 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
107 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
108
108
109 def test_alias_crash(self):
110 """Errors in prefilter can't crash IPython"""
111 ip.run_cell('%alias parts echo first %s second %s')
112 # capture stderr:
113 save_err = io.stderr
114 io.stderr = StringIO()
115 ip.run_cell('parts 1')
116 err = io.stderr.getvalue()
117 io.stderr = save_err
118 self.assertEqual(err.split(':')[0], 'ERROR')
119
120 def test_trailing_newline(self):
109 def test_trailing_newline(self):
121 """test that running !(command) does not raise a SyntaxError"""
110 """test that running !(command) does not raise a SyntaxError"""
122 ip.run_cell('!(true)\n', False)
111 ip.run_cell('!(true)\n', False)
@@ -48,16 +48,16 b' class DummyMagics(magic.Magics): pass'
48 def test_rehashx():
48 def test_rehashx():
49 # clear up everything
49 # clear up everything
50 _ip = get_ipython()
50 _ip = get_ipython()
51 _ip.alias_manager.alias_table.clear()
51 _ip.alias_manager.clear_aliases()
52 del _ip.db['syscmdlist']
52 del _ip.db['syscmdlist']
53
53
54 _ip.magic('rehashx')
54 _ip.magic('rehashx')
55 # Practically ALL ipython development systems will have more than 10 aliases
55 # Practically ALL ipython development systems will have more than 10 aliases
56
56
57 nt.assert_true(len(_ip.alias_manager.alias_table) > 10)
57 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
58 for key, val in _ip.alias_manager.alias_table.iteritems():
58 for name, cmd in _ip.alias_manager.aliases:
59 # we must strip dots from alias names
59 # we must strip dots from alias names
60 nt.assert_not_in('.', key)
60 nt.assert_not_in('.', name)
61
61
62 # rehashx must fill up syscmdlist
62 # rehashx must fill up syscmdlist
63 scoms = _ip.db['syscmdlist']
63 scoms = _ip.db['syscmdlist']
@@ -210,17 +210,17 b' class StoreMagics(Magics, Configurable):'
210 obj = ip.user_ns[args[0]]
210 obj = ip.user_ns[args[0]]
211 except KeyError:
211 except KeyError:
212 # it might be an alias
212 # it might be an alias
213 # This needs to be refactored to use the new AliasManager stuff.
213 name = args[0]
214 if args[0] in ip.alias_manager:
214 try:
215 name = args[0]
215 cmd = ip.alias_manager.retrieve_alias(name)
216 nargs, cmd = ip.alias_manager.alias_table[ name ]
216 except ValueError:
217 staliases = db.get('stored_aliases',{})
217 raise UsageError("Unknown variable '%s'" % name)
218 staliases[ name ] = cmd
218
219 db['stored_aliases'] = staliases
219 staliases = db.get('stored_aliases',{})
220 print "Alias stored: %s (%s)" % (name, cmd)
220 staliases[name] = cmd
221 return
221 db['stored_aliases'] = staliases
222 else:
222 print "Alias stored: %s (%s)" % (name, cmd)
223 raise UsageError("Unknown variable '%s'" % args[0])
223 return
224
224
225 else:
225 else:
226 modname = getattr(inspect.getmodule(obj), '__name__', '')
226 modname = getattr(inspect.getmodule(obj), '__name__', '')
@@ -27,7 +27,7 b' def test_store_restore():'
27 # Check restoring
27 # Check restoring
28 ip.magic('store -r')
28 ip.magic('store -r')
29 nt.assert_equal(ip.user_ns['foo'], 78)
29 nt.assert_equal(ip.user_ns['foo'], 78)
30 nt.assert_in('bar', ip.alias_manager.alias_table)
30 assert ip.alias_manager.is_alias('bar')
31 nt.assert_in(os.path.realpath(tmpd), ip.user_ns['_dh'])
31 nt.assert_in(os.path.realpath(tmpd), ip.user_ns['_dh'])
32
32
33 os.rmdir(tmpd)
33 os.rmdir(tmpd)
@@ -369,7 +369,7 b' class TerminalInteractiveShell(InteractiveShell):'
369
369
370
370
371 for name, cmd in aliases:
371 for name, cmd in aliases:
372 self.alias_manager.define_alias(name, cmd)
372 self.alias_manager.soft_define_alias(name, cmd)
373
373
374 #-------------------------------------------------------------------------
374 #-------------------------------------------------------------------------
375 # Things related to the banner and usage
375 # Things related to the banner and usage
General Comments 0
You need to be logged in to leave comments. Login now