Tuesday, March 31, 2009

Resumable IPython inside Blender Terminal

Would it not be nice if IPython could run inside the Blender terminal in such way that it will remember the namespace history in between sessions? Why IPython? It gives you auto completion, deep reloads, object introspection, input history, access to your operating system commands with python variables, auto indent, ... In case you are not convinced, read this tutorial, reference or watch these screencasts on showmedo.

Most Linux distributions ship IPython in their repositories. For example installing on Ubuntu is as easy as:
$ sudo apt-get install ipython
Getting IPython on Windows or Mac is simple if you have setuptools installed:
$ easy_install IPython
Windows users should install pyreadline as well for autocompletion. Check first in a terminal if IPython is correctly installed:
$ ipython
Python 2.5.2 (r252:60911, Oct 5 2008, 19:24:49)
Type "copyright", "credits" or "license" for more information.

IPython 0.8.4 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.

In [1]:
Save the following code as 'ipython_terminal.py' in your blender home script folder (~/.blender/scripts).
#!BPY

"""
Name: 'IPython (Terminal) - Enhanced Interactive Python Shell in Terminal'
Blender: 248
Group: 'System'
Tooltip: 'Interactive Python Console in terminal'
"""

__author__ = "Stani (SPE Python IDE)"
__url__ = ["pythonide.stani.be", "www.blender.org", "www.python.org"]
__bpydoc__ = """\
This only works if you started Blender from a terminal.
Otherwise Blender will freeze. The IPython console will
appear in the terminal. The namespace will be persistent
between console sessions within one Blender session.

Press Ctrl-D to pause the IPython session and return to Blender.
"""

# -*- coding: UTF-8 -*-

# ar - ARchitecture library
# Copyright (C) 2009 www.stani.be
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/

import sys

from IPython.Shell import IPShell

import bpy
import Blender

try:
shell = Blender.Registry.GetKey('ipython.terminal')['shell']
shell.IP.exit_now = False # resume
except TypeError:
sys_argv = sys.argv
sys.argv = ['/usr/bin/ipython']
shell = IPShell(user_ns={'Blender':Blender, 'bpy':bpy})
sys.argv = sys_argv
def pre_prompt_hook(ip, Blender=Blender, shell=shell):
Blender.Redraw()
Blender.Registry.SetKey('ipython.terminal', {'shell':shell})
shell.IP.set_hook('pre_prompt_hook',pre_prompt_hook)

shell.mainloop(banner=shell.IP.BANNER + shell.IP.banner2 +\
'\nPress Ctrl-D to pause the IPython session and ' +\
'return to Blender.\n')

Make sure you start Blender from a terminal and not from the start menu, as IPython will run in the terminal. You can start the IPython terminal from the Script window in Blender. (Scripts > System > Ipython (Terminal) ) Just like in my previous blog post, each time a Python statement is entered, the Blender window is updated. So you can move a cube and see the result, if you type:
In [1]: cube = bpy.data.objects['Cube']

In [2]: cube.LocX = -1
When you want to return to Blender, press Ctrl-D. If you restart later the IPython terminal, it will remember any commands you have typed or any variables you have declared (like cube in the example).

IPython has a different prompt which makes it easy to go back to previous input statements or output values:
In [1]: a=1

In [2]: print a
1

In [3]: a
Out[3]: 1

In [4]: exec _i2 # execute second command
1

In [5]: exec In[2:4] # execute multiple previous commands
1

In [6]: b=_3 # third ouput value

In [7]: a==b
Out[7]: True
If you prefer a standard python prompt (>>>), just enter '%doctest_mode':
In [1]: %doctest_mode
*** Pasting of code with ">>>" or "..." has been enabled.
Exception reporting mode: Plain
Doctest mode is: ON

>>>
For auto completion, press the TAB key:
In [1]: bpy.data.
bpy.data.__class__ bpy.data.curves
bpy.data.__delattr__ bpy.data.fonts
bpy.data.__dict__ bpy.data.groups
bpy.data.__doc__ bpy.data.images
bpy.data.__getattribute__ bpy.data.ipos
bpy.data.__hash__ bpy.data.lamps
bpy.data.__init__ bpy.data.lattices
bpy.data.__name__ bpy.data.materials
bpy.data.__new__ bpy.data.meshes
bpy.data.__reduce__ bpy.data.metaballs
bpy.data.__reduce_ex__ bpy.data.objects
bpy.data.__repr__ bpy.data.scenes
bpy.data.__setattr__ bpy.data.sounds
bpy.data.__str__ bpy.data.texts
bpy.data.actions bpy.data.textures
bpy.data.armatures bpy.data.worlds
bpy.data.cameras

In [1]: bpy.data.m
bpy.data.materials bpy.data.meshes bpy.data.metaballs

In [1]: from Blender import M
Material Mathutils Mesh Metaball Modifier
As shown in the last example auto completion works even for import statements.

Altough the Blender window updates itself, the Blender user interface is still irresponsive when running an IPython session. In a future blog post I'll show how to run IPython inside the Blender window in such way that the user interface stays fully responsive.

2 comments:

  1. thanks for this, it's very helpful!

    i suppose ipython can not be used in blender 2.5, since ipython does not yet support python 3?

    ReplyDelete
  2. @ammacdon
    Indeed. The ipython team is working on a py3 branch, so hopefully it will be possible again in the future.

    ReplyDelete

Filter by topic: spe, python, ubuntu