pythonmacrosipythonaliasipython-magic

How to write an ipython alias which executes in python instead of shell?


We can define an alias in ipython with the %alias magic function, like this:

>>> d
NameError: name 'd' is not defined
>>> %alias d date
>>> d
Fri May 15 00:12:20 AEST 2015

This escapes to the shell command date when you type d into ipython.

But I want to define an alias to execute some python code, in the current interpreter scope, rather than a shell command. Is that possible? How can we make this kind of alias?

I work in the interactive interpreter a lot, and this could save me a lot of commands I find myself repeating often, and also prevent some common typos.


Solution

  • The normal way to do this would be to simply write a python function, with a def. But if you want to alias a statement, rather than a function call, then it's actually a bit tricky.

    You can achieve this by writing a custom magic function. Here is an example, which effectively aliases the import statement to get, within the REPL.

    from IPython.core.magic import register_line_magic

    @register_line_magic
    def get(line):
        code = f"import {line}"
        print("-->", code)
        exec(code, globals())
    
    del get  # in interactive mode-remove from scope so function doesn't shadow magic
    

    edit: below is the previous code, for older versions of IPython

    from IPython.core.magic_arguments import argument, magic_arguments
    
    @magic_arguments()
    @argument('module')
    def magic_import(self, arg):
        code = 'import {}'.format(arg)
        print('--> {}'.format(code))
        self.shell.run_code(code)
    
    ip = get_ipython()
    ip.define_magic('get', magic_import)
    

    Now it is possible to execute get statements which are aliased to import statements.

    Demo:

    In [1]: get json
    --> import json
    
    In [2]: json.loads
    Out[2]: <function json.loads>
    
    In [3]: get potato
    --> import potato
    ---------------------------------------------------------------------------
    ImportError                               Traceback (most recent call last)
    <string> in <module>()
    
    ImportError: No module named potato
    
    In [4]: 
    

    Of course, this is extendible to arbitrary python code, and optional arguments are supported aswell.