Want to use Spring but don't want to use Java? Spring for Python is an Inversion of Control container for Python with several additional features such as aspect oriented programming. To learn more read on.
The original Spring, written for Java, is a framework which at its heart uses an "Inversion of Control" container (IoC). Inside of Spring, are several subframeworks for handling aspect oriented programming(aop), Data Access Framework (Dao), transaction management, a object to relational mapping(orm), and other features. The SpringPython framework, is a port of the original Java framework. Mind you, the developers of SpringPython didn't do a "direct port of existing code" from the Java counterpart, but rather rewrote it using Python idioms. SpringPython includes features for:
- Database Template
- Database Transactions
- Plugins/Command Line Tools
As with the Java version, Spring Python includes some samples; Petclinic, Spring Wiki, and Spring Bot. This article will cover mostly the basic use of the Inversion Of Control container. The purpose of this article is to get you up and using SpringPython quickly without having to parse the in depth theory.
To get started, you will need Pyro (Python Remote Objects) from http://pyro.sourceforge .net, which is "an object-oriented form of RPC". Think, a Python version of Remote Method Invocation (RMI). You will also need Amara from http://wiki.xml3k.org/ Amara for XML processing. Amara itself has some dependencies, so if you want to make your life easier I highly recommend downloading and installing Setuptools from http://pypi .python.org/pypi/setuptools. Setuptools has easy_install which will take care of the dependencies.
$ sudo easy_install Amara-220.127.116.11-py2.5.egg
Listing 1. The dollar sign represents the Linux command line.
Inversion of Control and Dependency Injection
Inversion of Control is a design pattern that applies the Hollywood principle, "Don't call us, we'll call you", in other words, the flow of control of a system is inverted. Using an adapted example from Martin Fowler, in a simple program that gets input from the command line, the program holds the control. Here, my program controls the flow.
name = raw_input('What is your name? ')
quest = raw_input('What is your quest? ')
Listing 2. A simple procedural program that accepts some input, and processes the information. Martin Fowler's original example uses Ruby.
In a GUI run program, the control is held by the windowing system. Again paraphrasing Martin Fowler's example, with Python and Tkinter:
from Tkinter import *
print "name is ", name
print "quest is ", quest
root = Tk()
name_label = Label(root, text="What is Your Name?").pack()
name = Entry(root)
name.bind("<FOCUSOUT>", (lambda event: process_name(name.get())))
quest_label = Label(root, text="What is Your Quest?").pack()
quest = Entry(root)
quest.bind("<FOCUSOUT>", (lambda event : process_quest(quest.get())))
Listing 3. Instead of the program controlling the flow, now the windowing system takes the control
So, the flow of control was "Inverted"; instead of me doing the calling, the windowing system does the calling. Spring is known as a Inversion of Control container, abbreviated as IoC, with some added features, such as aspect oriented programming.
In the case of Spring, what's being inverted is the process of obtaining an external dependency. This is a special case of IoC is known as Dependency Injection, or DI. In other words, a dependency is "injected" into a component. In practice, as you're about to see, this is much simpler than it sounds.
The DI pattern has three parts; a dependent, its dependencies and an injector or container. Figure 1 illustrates this relationship. Objects A, B, and C (The dependencies) are injected into Component D (The dependant ) via the container.
Figure 1. A simplified illustration of dependency injection.
A great advantage to using this pattern is being able to feed a program mock objects, which can be replaced later, without having to change the code. This automatically lends itself well for unit testing.
Getting Started With Spring Python
In our example, we'll create a program that requires a
logger. For whatever reason, we want to use a mock object,
that can easily be replaced later. The first step is to
define our Spring object, which will be injected at
execution time. The original Java Spring uses "Beans", which
is really just a POJO or plain old Java object. I suspect
that plain old Python objects (POPOs!) probably won't catch
on; the equivalent in Spring Python is simply Objects. I'll
use the term Spring Object to avoid confusion. Listing 4
shows a Python class for our logger. Note, the file name is
print "writing to log:", self.msg
Listing 4. Our simple Spring Object,
, in module
This Spring Object has two properties, Destination and
Msg, as well as a write method. Each property has a
Different from the Java implementation of Spring,
setter's aren't necessary. The Spring Objects
are defined in an external XML file, shown in Listing 5.
The XML format is very similar to the Java Spring
version. Each object, defined with the <object> tag,
has an id, or object name, its deriving class, and the
scope. Only two scopes are possible, prototype or singleton.
In listing 5 we define an object called logger which is of
Lumber.Logger. We use the property "destination"
with a value of
<?xml version="1.0" encoding="UTF-8"?>
<object id="logger" class="Lumber.Logger" scope="prototype">
Listing 5. Our XML configuration file,
applicationContext.xml, with property destination
Because we're using Python, we can dynamically add
Setter's in the Spring Object are
not necessary, although, if that's your style of programming
feel free to add those methods. Now that we have a Spring
Object, and the configuration for it, we can create the
sample app, where we'll inject the dependency,
from springpython.context import ApplicationContext
from springpython.config import XMLConfig
container = ApplicationContext(XMLConfig("applicationContext.xml"))
logger = container.get_object("logger")
print "all messages will be logged into ", logger.getDestination()
logger.msg = "A critical error has occurred of type xyz"
Listing 6. The main program. A spring container is created
create our container, which will be used to inject the
logger defined in the XML configuration file. As you can see
from the first print message, logger is indeed the object
defined externally, and we can call it's method
getDestination(). In our sample application, we
log a message after an exception is raised. We add the
property msg, with a string value, and then call the method
In a real world application, after development of the
main program is finished, the simplistic
Lumber.Logger class can be replaced with a
complete, and sophisticated logging system. For example,
that will be able to write data over a network. The only
requirements in our sample application is that the new
logger have a
write() method (Think, design by contract).
I don't believe that DI should be used everywhere all the
time, but I think there are advantages to be gained. If you
didn't already know, there's a pretty viscous debate going
on about whether DI makes any sense in dynamic languages
like Python and Ruby. I'll probably get hate mail for
writing this article.
Besides that minor point, if you can't wrap your head
around the idea of inversion of control, try to look at it
from implementation point of view. You have a Python class
that will be instantiated by the Spring container. Define
your class, create the XML config file with the initial
values that you'd like, create a Spring container inside of
the dependent component, get the object via the container.
Now you can use this object like any other Python object.
That's it, really.
The Spring Python home page
A great opinion piece on why, and when, you should use Spring Python
Martin Fowler's explanation on Inversion of Control and Dependency Injection
Another article by Martin Fowler on both DI and IoC
A Wikipedia article on DI, mentions some other Python frameworks