##// END OF EJS Templates
Changes to Alias API after discussion with Fernando
Thomas Kluyver -
Show More
@@ -20,18 +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.error import UsageError
28 from IPython.core.error import UsageError
31 from IPython.core.splitinput import split_user_input
32
29
33 from IPython.utils.traitlets import List, Instance
30 from IPython.utils.traitlets import List, Instance
34 from IPython.utils.warn import warn, error
31 from IPython.utils.warn import error
35
32
36 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
37 # Utilities
34 # Utilities
@@ -105,19 +102,50 b' class AliasError(Exception):'
105 class InvalidAliasError(AliasError):
102 class InvalidAliasError(AliasError):
106 pass
103 pass
107
104
108 class AliasCaller(object):
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
109 def __init__(self, shell, name, cmd):
114 def __init__(self, shell, name, cmd):
110 self.shell = shell
115 self.shell = shell
111 self.name = name
116 self.name = name
112 self.cmd = cmd
117 self.cmd = cmd
113 self.nargs = cmd.count('%s')
118 self.nargs = self.validate()
114 if (self.nargs > 0) and (cmd.find('%l') >= 0):
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):
115 raise InvalidAliasError('The %s and %l specifiers are mutually '
141 raise InvalidAliasError('The %s and %l specifiers are mutually '
116 'exclusive in alias definitions.')
142 'exclusive in alias definitions.')
117
143
144 return nargs
145
118 def __repr__(self):
146 def __repr__(self):
119 return "<alias {} for {!r}>".format(self.name, self.cmd)
147 return "<alias {} for {!r}>".format(self.name, self.cmd)
120
148
121 def __call__(self, rest=''):
149 def __call__(self, rest=''):
122 cmd = self.cmd
150 cmd = self.cmd
123 nargs = self.nargs
151 nargs = self.nargs
@@ -135,7 +163,7 b' class AliasCaller(object):'
135 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
163 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
136 (self.name, nargs, len(args)))
164 (self.name, nargs, len(args)))
137 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
165 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
138
166
139 self.shell.system(cmd)
167 self.shell.system(cmd)
140
168
141 #-----------------------------------------------------------------------------
169 #-----------------------------------------------------------------------------
@@ -150,34 +178,19 b' class AliasManager(Configurable):'
150
178
151 def __init__(self, shell=None, **kwargs):
179 def __init__(self, shell=None, **kwargs):
152 super(AliasManager, self).__init__(shell=shell, **kwargs)
180 super(AliasManager, self).__init__(shell=shell, **kwargs)
153 self.init_exclusions()
181 # For convenient access
182 self.linemagics = self.shell.magics_manager.magics['line']
154 self.init_aliases()
183 self.init_aliases()
155
184
156 @property
157 def aliases(self):
158 linemagics = self.shell.magics_manager.magics['line']
159 return [(n, func.cmd) for (n, func) in linemagics.items()
160 if isinstance(func, AliasCaller)]
161
162 def init_exclusions(self):
163 # set of things NOT to alias (keywords, builtins and some magics)
164 no_alias = {'cd','popd','pushd','dhist','alias','unalias'}
165 no_alias.update(set(keyword.kwlist))
166 no_alias.update(set(__builtin__.__dict__.keys()))
167 self.no_alias = no_alias
168
169 def init_aliases(self):
185 def init_aliases(self):
170 # Load default aliases
186 # Load default & user aliases
171 for name, cmd in self.default_aliases:
187 for name, cmd in self.default_aliases + self.user_aliases:
172 self.soft_define_alias(name, cmd)
188 self.soft_define_alias(name, cmd)
173
189
174 # Load user aliases
190 @property
175 for name, cmd in self.user_aliases:
191 def aliases(self):
176 self.soft_define_alias(name, cmd)
192 return [(n, func.cmd) for (n, func) in self.linemagics.items()
177
193 if isinstance(func, Alias)]
178 def clear_aliases(self):
179 for name, cmd in self.aliases:
180 self.undefine_alias(name)
181
194
182 def soft_define_alias(self, name, cmd):
195 def soft_define_alias(self, name, cmd):
183 """Define an alias, but don't raise on an AliasError."""
196 """Define an alias, but don't raise on an AliasError."""
@@ -192,46 +205,33 b' class AliasManager(Configurable):'
192 This will raise an :exc:`AliasError` if there are validation
205 This will raise an :exc:`AliasError` if there are validation
193 problems.
206 problems.
194 """
207 """
195 self.validate_alias(name, cmd)
208 caller = Alias(shell=self.shell, name=name, cmd=cmd)
196 caller = AliasCaller(shell=self.shell, name=name, cmd=cmd)
197 self.shell.magics_manager.register_function(caller, magic_kind='line',
209 self.shell.magics_manager.register_function(caller, magic_kind='line',
198 magic_name=name)
210 magic_name=name)
199
211
212 def get_alias(self, name):
213 """Return an alias, or None if no alias by that name exists."""
214 aname = self.linemagics.get(name, None)
215 return aname if isinstance(aname, Alias) else None
216
217 def is_alias(self, name):
218 """Return whether or not a given name has been defined as an alias"""
219 return self.get_alias(name) is not None
220
200 def undefine_alias(self, name):
221 def undefine_alias(self, name):
201 linemagics = self.shell.magics_manager.magics['line']
222 if self.is_alias(name):
202 caller = linemagics.get(name, None)
223 del self.linemagics[name]
203 if isinstance(caller, AliasCaller):
204 del linemagics[name]
205 else:
224 else:
206 raise ValueError('%s is not an alias' % name)
225 raise ValueError('%s is not an alias' % name)
207
226
208 def validate_alias(self, name, cmd):
227 def clear_aliases(self):
209 """Validate an alias and return the its number of arguments."""
228 for name, cmd in self.aliases:
210 if name in self.no_alias:
229 self.undefine_alias(name)
211 raise InvalidAliasError("The name %s can't be aliased "
230
212 "because it is a keyword or builtin." % name)
213 try:
214 caller = self.shell.magics_manager.magics['line'][name]
215 except KeyError:
216 pass
217 else:
218 if not isinstance(caller, AliasCaller):
219 raise InvalidAliasError("The name %s can't be aliased "
220 "because it is another magic command." % name)
221 if not (isinstance(cmd, basestring)):
222 raise InvalidAliasError("An alias command must be a string, "
223 "got: %r" % cmd)
224 return True
225
226 def retrieve_alias(self, name):
231 def retrieve_alias(self, name):
227 """Retrieve the command to which an alias expands."""
232 """Retrieve the command to which an alias expands."""
228 caller = self.shell.magics_manager.magics['line'].get(name, None)
233 caller = self.get_alias(name)
229 if isinstance(caller, AliasCaller):
234 if caller:
230 return caller.cmd
235 return caller.cmd
231 else:
236 else:
232 raise ValueError('%s is not an alias' % name)
237 raise ValueError('%s is not an alias' % name)
233
234 def is_alias(self, name):
235 """Return whether or not a given name has been defined as an alias"""
236 caller = self.shell.magics_manager.magics['line'].get(name, None)
237 return isinstance(caller, AliasCaller)
@@ -26,7 +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
29 from IPython.core.alias import AliasError, Alias
30 from IPython.core.error import UsageError
30 from IPython.core.error import UsageError
31 from IPython.core.magic import (
31 from IPython.core.magic import (
32 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
@@ -200,7 +200,7 b' class OSMagics(Magics):'
200 else:
200 else:
201 syscmdlist.append(ff)
201 syscmdlist.append(ff)
202 else:
202 else:
203 no_alias = self.shell.alias_manager.no_alias
203 no_alias = Alias.blacklist
204 for pdir in path:
204 for pdir in path:
205 os.chdir(pdir)
205 os.chdir(pdir)
206 for ff in os.listdir(pdir):
206 for ff in os.listdir(pdir):
@@ -210,7 +210,6 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.
214 name = args[0]
213 name = args[0]
215 try:
214 try:
216 cmd = ip.alias_manager.retrieve_alias(name)
215 cmd = ip.alias_manager.retrieve_alias(name)
General Comments 0
You need to be logged in to leave comments. Login now