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

Question:

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.

Asked By: wim

||

Answers:

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.

Answered By: wim

I don’t know since when IPython provides with macro. And now you can simply do this:

ipy = get_ipython()
ipy.define_macro('d', 'date')

You can put this code into any file located in ~/.ipython/profile_default/startup/, and then this macro will be automatically available when you start IPython.

However, a macro doesn’t accept arguments. So pleaes keep this in mind before you choose to define a macro.

Answered By: SleepyBag