##// END OF EJS Templates
Changes to Alias API after discussion with Fernando
Thomas Kluyver -
Show More
@@ -20,18 +20,15 b' Authors:'
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 import __builtin__
24 import keyword
25 23 import os
26 24 import re
27 25 import sys
28 26
29 27 from IPython.config.configurable import Configurable
30 28 from IPython.core.error import UsageError
31 from IPython.core.splitinput import split_user_input
32 29
33 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 34 # Utilities
@@ -105,19 +102,50 b' class AliasError(Exception):'
105 102 class InvalidAliasError(AliasError):
106 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 114 def __init__(self, shell, name, cmd):
110 115 self.shell = shell
111 116 self.name = name
112 117 self.cmd = cmd
113 self.nargs = cmd.count('%s')
114 if (self.nargs > 0) and (cmd.find('%l') >= 0):
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):
115 141 raise InvalidAliasError('The %s and %l specifiers are mutually '
116 'exclusive in alias definitions.')
117
142 'exclusive in alias definitions.')
143
144 return nargs
145
118 146 def __repr__(self):
119 147 return "<alias {} for {!r}>".format(self.name, self.cmd)
120
148
121 149 def __call__(self, rest=''):
122 150 cmd = self.cmd
123 151 nargs = self.nargs
@@ -135,7 +163,7 b' class AliasCaller(object):'
135 163 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
136 164 (self.name, nargs, len(args)))
137 165 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
138
166
139 167 self.shell.system(cmd)
140 168
141 169 #-----------------------------------------------------------------------------
@@ -150,34 +178,19 b' class AliasManager(Configurable):'
150 178
151 179 def __init__(self, shell=None, **kwargs):
152 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 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 185 def init_aliases(self):
170 # Load default aliases
171 for name, cmd in self.default_aliases:
186 # Load default & user aliases
187 for name, cmd in self.default_aliases + self.user_aliases:
172 188 self.soft_define_alias(name, cmd)
173 189
174 # Load user aliases
175 for name, cmd in self.user_aliases:
176 self.soft_define_alias(name, cmd)
177
178 def clear_aliases(self):
179 for name, cmd in self.aliases:
180 self.undefine_alias(name)
190 @property
191 def aliases(self):
192 return [(n, func.cmd) for (n, func) in self.linemagics.items()
193 if isinstance(func, Alias)]
181 194
182 195 def soft_define_alias(self, name, cmd):
183 196 """Define an alias, but don't raise on an AliasError."""
@@ -192,46 +205,33 b' class AliasManager(Configurable):'
192 205 This will raise an :exc:`AliasError` if there are validation
193 206 problems.
194 207 """
195 self.validate_alias(name, cmd)
196 caller = AliasCaller(shell=self.shell, name=name, cmd=cmd)
208 caller = Alias(shell=self.shell, name=name, cmd=cmd)
197 209 self.shell.magics_manager.register_function(caller, magic_kind='line',
198 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 221 def undefine_alias(self, name):
201 linemagics = self.shell.magics_manager.magics['line']
202 caller = linemagics.get(name, None)
203 if isinstance(caller, AliasCaller):
204 del linemagics[name]
222 if self.is_alias(name):
223 del self.linemagics[name]
205 224 else:
206 225 raise ValueError('%s is not an alias' % name)
207 226
208 def validate_alias(self, name, cmd):
209 """Validate an alias and return the its number of arguments."""
210 if name in self.no_alias:
211 raise InvalidAliasError("The name %s can't be aliased "
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
227 def clear_aliases(self):
228 for name, cmd in self.aliases:
229 self.undefine_alias(name)
230
226 231 def retrieve_alias(self, name):
227 232 """Retrieve the command to which an alias expands."""
228 caller = self.shell.magics_manager.magics['line'].get(name, None)
229 if isinstance(caller, AliasCaller):
233 caller = self.get_alias(name)
234 if caller:
230 235 return caller.cmd
231 236 else:
232 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 26 from IPython.core import magic_arguments
27 27 from IPython.core import oinspect
28 28 from IPython.core import page
29 from IPython.core.alias import AliasError
29 from IPython.core.alias import AliasError, Alias
30 30 from IPython.core.error import UsageError
31 31 from IPython.core.magic import (
32 32 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
@@ -200,7 +200,7 b' class OSMagics(Magics):'
200 200 else:
201 201 syscmdlist.append(ff)
202 202 else:
203 no_alias = self.shell.alias_manager.no_alias
203 no_alias = Alias.blacklist
204 204 for pdir in path:
205 205 os.chdir(pdir)
206 206 for ff in os.listdir(pdir):
@@ -210,7 +210,6 b' class StoreMagics(Magics, Configurable):'
210 210 obj = ip.user_ns[args[0]]
211 211 except KeyError:
212 212 # it might be an alias
213 # This needs to be refactored to use the new AliasManager stuff.
214 213 name = args[0]
215 214 try:
216 215 cmd = ip.alias_manager.retrieve_alias(name)
General Comments 0
You need to be logged in to leave comments. Login now