http://www.developer.com/

Back to article

A Quick Introduction to the Spring Python Framework


November 9, 2009

Introduction

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:

  • IoC
  • AOP
  • Database Template
  • Database Transactions
  • Security
  • Remoting
  • 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.

Dependencies

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-1.2.0.2-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? ')
  doSomethingWithName(name)
  quest = raw_input('What is your quest? ')
  doSomethingWithQuest(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 *
  
  def process_name(name):
      print "name is ", name
  
  def process_quest(quest):
      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())))
  name.pack()
  quest_label = Label(root, text="What is Your Quest?").pack()
  quest = Entry(root)
  quest.bind("<FOCUSOUT>", (lambda event : process_quest(quest.get())))
  quest.pack()
  root.mainloop()

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 Lumber.

  class Logger:
      def getDestination(self):
          return self.destination 
  
      def write(self):
          print "writing to log:", self.msg

Listing 4. Our simple Spring Object, Logger, in module Lumber.

This Spring Object has two properties, Destination and Msg, as well as a write method. Each property has a corresponding get and set method. 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 the class Lumber.Logger. We use the property "destination" with a value of "<CODE>/who/knows/where/loggit.txt</CODE>".

  <?xml version="1.0" encoding="UTF-8"?>
  <objects xmlns="http://www.springframework.org/springpython/schema/objects"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/springpython/schema/objects
   http://springpython.webfactional.com/schema/context/spring-python-context-1.0.xsd">
           
    <object id="logger" class="Lumber.Logger" scope="prototype">
      <property name="destination"     
                value="/who/knows/where/loggit.txt"/>
    </object>
  </objects>

Listing 5. Our XML configuration file, applicationContext.xml, with property destination

Because we're using Python, we can dynamically add properties. 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, Lumber.Logger.

  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()
  
  try:
      print unboundVariableWatchMeBlowUp 
  except:
      logger.msg = "A critical error has occurred of type xyz"
      logger.write() 

Listing 6. The main program. A spring container is created

Using springpython.context.ApplicationContext() we 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 write().

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 getDestination() and write() method (Think, design by contract).

Conclusion

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.

References

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

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date