From baba1f535e7d0dc845bf2828135198da81fabcda 2013-09-19 17:56:11 From: Thomas Kluyver Date: 2013-09-19 17:56:11 Subject: [PATCH] Initial changes to make alias system use magics --- diff --git a/IPython/core/alias.py b/IPython/core/alias.py index 0905c19..cceab0f 100644 --- a/IPython/core/alias.py +++ b/IPython/core/alias.py @@ -104,6 +104,35 @@ class AliasError(Exception): class InvalidAliasError(AliasError): pass +class AliasCaller(object): + def __init__(self, shell, cmd): + self.shell = shell + self.cmd = cmd + self.nargs = cmd.count('%s') + if (self.nargs > 0) and (cmd.find('%l') >= 0): + raise InvalidAliasError('The %s and %l specifiers are mutually ' + 'exclusive in alias definitions.') + + def __call__(self, rest=''): + cmd = self.cmd + nargs = self.nargs + # Expand the %l special to be the user's input line + if cmd.find('%l') >= 0: + cmd = cmd.replace('%l', rest) + rest = '' + if nargs==0: + # Simple, argument-less aliases + cmd = '%s %s' % (cmd, rest) + else: + # Handle aliases with positional arguments + args = rest.split(None, nargs) + if len(args) < nargs: + raise AliasError('Alias <%s> requires %s arguments, %s given.' % + (alias, nargs, len(args))) + cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:])) + + self.shell.system(cmd) + #----------------------------------------------------------------------------- # Main AliasManager class #----------------------------------------------------------------------------- @@ -117,7 +146,7 @@ class AliasManager(Configurable): def __init__(self, shell=None, **kwargs): super(AliasManager, self).__init__(shell=shell, **kwargs) self.alias_table = {} - self.exclude_aliases() + self.init_exclusions() self.init_aliases() def __contains__(self, name): @@ -127,9 +156,9 @@ class AliasManager(Configurable): def aliases(self): return [(item[0], item[1][1]) for item in self.alias_table.iteritems()] - def exclude_aliases(self): + def init_exclusions(self): # set of things NOT to alias (keywords, builtins and some magics) - no_alias = set(['cd','popd','pushd','dhist','alias','unalias']) + no_alias = {'cd','popd','pushd','dhist','alias','unalias'} no_alias.update(set(keyword.kwlist)) no_alias.update(set(__builtin__.__dict__.keys())) self.no_alias = no_alias @@ -159,12 +188,18 @@ class AliasManager(Configurable): This will raise an :exc:`AliasError` if there are validation problems. """ - nargs = self.validate_alias(name, cmd) - self.alias_table[name] = (nargs, cmd) + self.validate_alias(name, cmd) + caller = AliasCaller(shell=self.shell, cmd=cmd) + self.shell.magics_manager.register_function(caller, magic_kind='line', + magic_name=name) def undefine_alias(self, name): - if name in self.alias_table: - del self.alias_table[name] + linemagics = self.shell.magics_manager.magics['line'] + caller = linemagics.get(name, None) + if isinstance(caller, AliasCaller): + del linemagics[name] + else: + raise ValueError('%s is not an alias' % name) def validate_alias(self, name, cmd): """Validate an alias and return the its number of arguments.""" @@ -174,11 +209,7 @@ class AliasManager(Configurable): if not (isinstance(cmd, basestring)): raise InvalidAliasError("An alias command must be a string, " "got: %r" % cmd) - nargs = cmd.count('%s') - if nargs>0 and cmd.find('%l')>=0: - raise InvalidAliasError('The %s and %l specifiers are mutually ' - 'exclusive in alias definitions.') - return nargs + return True def call_alias(self, alias, rest=''): """Call an alias given its name and the rest of the line.""" diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 5c9a7a4..a65a2a8 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -470,7 +470,6 @@ class InteractiveShell(SingletonConfigurable): # because it and init_io have to come after init_readline. self.init_user_ns() self.init_logger() - self.init_alias() self.init_builtins() # The following was in post_config_initialization @@ -502,6 +501,7 @@ class InteractiveShell(SingletonConfigurable): self.init_displayhook() self.init_latextool() self.init_magics() + self.init_alias() self.init_logstart() self.init_pdb() self.init_extension_manager() @@ -1940,7 +1940,7 @@ class InteractiveShell(SingletonConfigurable): self.Completer = IPCompleter(shell=self, namespace=self.user_ns, global_namespace=self.user_global_ns, - alias_table=self.alias_manager.alias_table, + #alias_table=self.alias_manager.alias_table, use_readline=self.has_readline, parent=self, ) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 71f0035..d23bb1f 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -26,6 +26,7 @@ from pprint import pformat from IPython.core import magic_arguments from IPython.core import oinspect from IPython.core import page +from IPython.core.alias import AliasError from IPython.core.error import UsageError from IPython.core.magic import ( Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic @@ -113,10 +114,14 @@ class OSMagics(Magics): # Now try to define a new one try: alias,cmd = par.split(None, 1) - except: - print oinspect.getdoc(self.alias) - else: - self.shell.alias_manager.soft_define_alias(alias, cmd) + except TypeError: + print(oinspect.getdoc(self.alias)) + return + + try: + self.shell.alias_manager.define_alias(alias, cmd) + except AliasError as e: + print(e) # end magic_alias @line_magic @@ -124,7 +129,12 @@ class OSMagics(Magics): """Remove an alias""" aname = parameter_s.strip() - self.shell.alias_manager.undefine_alias(aname) + try: + self.shell.alias_manager.undefine_alias(aname) + except ValueError as e: + print(e) + return + stored = self.shell.db.get('stored_aliases', {} ) if aname in stored: print "Removing %stored alias",aname