Spring Python 1.1

By Greg L. Turnquist
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Getting Started with Spring Python

About this book

Spring Python captures the concepts of the Spring Framework and Spring Security and brings them to the world of Python and provides many functional parts to assemble applications. Spring Python is all about using the many useful features of Spring to the fullest and making these features available when working with Python.

Get to grips with all of the concepts of Spring and apply these to the language and environment of Python to develop powerful applications for your own personal requirements. The book provides an introduction to Spring Python and steadily takes you towards the advanced features that this integration has to offer.

Spring uses the Java programming language. Spring Python, the first Spring extension to go live, allows developers to make maximum use of Spring features in Python. This book starts off by introducing each of the core building blocks of Spring Python using real code examples and high-level diagrams. It explores the various concepts of Spring Python with the help of examples and case studies and focuses on vital Spring Python features to make the lives of Python and Java developers simple. The early chapters cover simple applications with simple operations including data access, and then subsequent chapters scale up to multi-node, secured, transactional applications stopping short of very advanced level complexity.

Publication date:
May 2010
Publisher
Packt
Pages
264
ISBN
9781849510660

 

Chapter 1. Getting Started with Spring Python

Spring Python takes the concepts of the Spring Framework and Spring Security, and brings them to the world of Python. It isn't a simple line-by-line port of the code. Instead, it takes some powerful ideas that were discovered in the realm of Java, and pragmatically applies them in the world of Python.

Spring (Java) provides many simple, easy-to-use functional parts to assemble applications instead of a monolithic framework to extend. Spring Python uses this same approach. This means we can use as little or as much Spring Python as we need to get the job done for each Python application.

In this chapter, we will learn:

  • About Spring Python's a non-invasive API which makes it easy to use other libraries without having to make major changes to your own code base

  • How Spring Python uses inversion of control to decouple object creation from object usage to empower the developer

  • How Spring Python provides the means to help professional Python developers by offering a non-invasive API to easily access advanced services

  • The ways in which Spring Python offers professional Java developers an easy way to mix Python and Java together through the combination of Python/Jython/Java

  • How to install the library from both binary and source code

  • How extensible Spring Python is, and also some links to the Spring Python community

 

Spring Python for Python developers


You have already picked one of the most popular and technically powerful dynamic languages to develop software, Python. Spring Python makes it even easier to solve common problems encountered by Python developers every day.

Exploring Spring Python's non-invasive nature

Spring Python has a non-invasive nature, which means it is easy to adopt the parts that meet your needs, without rewriting huge blocks of code. For example, Pyro (http://pyro.sourceforge.net) is a 3rd party library that provides an easy way to make remote procedure calls.

In order to demonstrate the Spring way of non-invasiveness, let's code a simple service, publish it as a web service using Pyro's API, and then publish it using Spring Python's wrapper around Pyro. This will show the difference in how Spring Python simplifies API access for us, and how it makes the 3rd party library easier to use without as much rework to our own code.

  1. First, let's write a simple service that parses out the parameters from a web request string:

    class ParamParser(object):
        def parse_web_parms(self, parm):
            return [tuple(p.split("=")) for p in parm.split("&")]
  2. Now we can write a simple, functional piece of code that uses our service in order to have a working version.

    parser = ParamParser()
    parser.parse_web_parms("pages=5&article=Spring_Python")

    This is just instantiating the ParamParser and accessing the function. To make this a useful internet service, it needs to be instantiated on a central server and should be configured to listen for calls from clients.

  3. The next step is to advertise it as a web service using the API of Pyro. This will make it reachable by multiple Pyro clients. To do this, we define a daemon which will host our service on port 9000 and initialize it.

    import Pyro
    
    daemon = Pyro.core.Daemon(host="localhost", port="9000")
    Pyro.core.initServer()
  4. Next, we create a Pyro object instance to act as proxy to our service as well as an instance of our ParamParser. We configure the proxy to delegate all method calls to our service.

    pyro_proxy = Pyro.core.ObjBase()
    parser = ParamParser()
    pyro_proxy.delegateTo(parser)
  5. Finally, we register the pyro_proxy object with the daemon, and startup a listen-dispatch loop so that it's ready to handle requests:

    daemon.connect(pyro_proxy, "mywebservice")
    daemon.requestLoop(True)

When we run this server code, an instance of our ParamParser will be created and advertised at PYROLOC://localhost:9000/mywebservice.

To make this service complete, we need to create a Pyro client that will call into our service. The proxy seamlessly transfers Python objects over the wire using the Pyro library, in this case the tuple of request parameters.

import Pyro

url_base = "PYROLOC://localhost:9000"
client_proxy = Pyro.core.getProxyForURI(  \
    url_base + "/mywebservice")
print client_proxy.parse_web_parms(  \
    "pages=5&article=Spring_Python")

The Pyro library is easy to use. One key factor is how our ParamParser never gets tightly coupled to the Pyro machinery used to serve it to remote clients. However, it's very invasive.

What if we had already developed a simple application on a single machine with lots of methods making use of our utility? In order to convert our application into a client-server application, we would have to rewrite it to use the Pyro client proxy pattern everywhere that it was called. If we miss any instances, we will have bugs that need to be cleaned up. If we had written automated tests, they would also have to be rewritten as well. Converting a simple, one-machine application into a multi-node application can quickly generate a lot of work.

That is where Spring Python comes in. It provides a different way of creating objects which makes it easy for us to replace a local object with a remoting mechanism such as Pyro. Later on, we will explore the concepts of Spring Python's container in more detail.

Let's utilize Spring Python's container to create our parser and also to serve it up with Pyro.

from springpython.config import PythonConfig
from springpython.config import Object
from springpython.remoting.pyro import PyroServiceExporter
from springpython.remoting.pyro import PyroProxyFactory

class WebServiceContainer(PythonConfig):
    def __init__(self):
        super(WebServiceContainer, self).__init__()

    @Object(lazy_init=True)
    def my_web_server(self):
        return PyroServiceExporter(service=ParamParser(),
                                   service_name="mywebservice",
                                   service_port=9000)

    @Object(lazy_init=True)
    def my_web_client(self):
        myService = PyroProxyFactory()
        myService.service_url="PYROLOC://localhost:9000/mywebservice"
        return myService

With this container definition, it is easy to write both a server application as well as a client application. To spin up one instance of our Pyro server, we use the following code:

  from springpython.context import ApplicationContext
  container = ApplicationContext(WebServiceContainer())
  container.get_object("my_web_server")

The client application looks very similar.

  from springpython.context import ApplicationContext
  container = ApplicationContext(WebServiceContainer())	
  myService = container.get_object("my_web_client")
  myService.parse_web_parms("pages=5&article=Spring_Python")

The Spring Python container works by containing all the definitions for creating key objects. We create an instance of the container, ask it for a specific object, and then use it.

This easily looks like just as much (if not more) code than using the Pyro API directly. So why is it considered less invasive?

Looking at the last block of code, we can see that we are no longer creating the parser or the Pyro proxy. Instead, we are relying on the container to create it for us. The Spring Python container decouples the creation of our parser, whether its for a local application, or if it uses Pyro to join them remotely. The server application doesn't know that it is being exported as a Pyro service, because all that information is stored in the WebServiceContainer. Any changes made to the container definition aren't seen by the server application code.

The same can be said for the client. By putting creation of the client inside the container, we don't have to know whether we are getting an instance of our service or a proxy. This means that additional changes can be made inside the definition of the container of Spring Python, without impacting our client and server apps. This makes it easy to split the server and client calls into separate scripts to be run in separate instances of Python or on separate nodes in our enterprise.

This demonstrates how it is possible to mix in remoting to our existing application. By using this pattern of delegating creation of key objects to the container, it is easy to start with simple object creation, and then layer on useful services such as remoting. Later in this book, we will also see how this makes it easy to add other services like transactions and security. Due to Spring Python's open ended design, we can easily create new services and add them on without having to alter the original framework.

Adding in some useful templates

In addition to the non-invasive ability to mix in services, Spring Python has several utilities that ease the usage of low level APIs through a template pattern. The template pattern involves capturing a logical flow of steps. What occurs at each step is customizable by the developer, while still maintaining the same overall sequence.

One example where a template would be useful is for writing a SQL query. Coding SQL queries by hand using Python's database API (http://www.python.org/dev/peps/pep-0249) is very tedious. We must properly handle errors and harvest the results. The extra code involved with connecting things together and handling issues is commonly referred to as plumbing code. Let's look at the following code to see how Python's database API functions.

The more plumbing code we have to maintain, the higher the cost. Having an application with dozens or hundreds of queries can become unwieldy, even cost prohibitive to maintain.

  1. Using Python's database API, we only have to write the following code once for setup.

    	### One time setup
    	import MySQLdb
    	conn = MySQLdb.connection(username="me",
    	                          password"secret",
    	                          hostname="localhost",
    	                          db="springpython")
  2. Now let's use Python's database API to perform a single query.

    	### Repeated for every query
    	cursor = conn.cursor()
    	results = []
    	try:
    	  cursor.execute("""select title, air_date, episode_number, writer
    	                      from tv_shows where name = %s""",
    	                      ("Monty Python",))
    	    for row in cursor.fetchall():
    	        tvShow = TvShow(title=row[0],
    	                        airDate=row[1],
    	                        episodeNumber=row[2],
    	                        writer=row[3])
    	        results.append(tvShow)
    	finally:
    	    try:
    	        cursor.close()
    	    except Exception:
    	        pass
    	conn.close()
    	return results

    The specialized code we wrote to look up TV shows is contained in the execute statement and also the part that creates an instance of TvShow. The rest is just plumbing code needed to handle errors, manage the database cursor, and iterate over the results.

    This may not look like much, but have you ever developed an application with just one SQL query? We could have dozens or even hundreds of queries, and having to repeatedly code these steps can become overwhelming. Spring Python's DatabaseTemplate lets us just inject the query string and and a row mapper to reduce the total amount of code that we need to write.

  3. We need a slightly different setup than before.

    	"""One time setup"""
    	from springpython.database.core import *
    	from springpython.database.factory import *
    	connectionFactory = MySQLConnectionFactory(username="me",
    	                                           password="secret",
    	                                           hostname="localhost",
    	                                           db="springpython")
  4. We also need to define a mapping to generate our TvShow objects.

    	class TvShowMapper(RowMapper):
    	    def map_row(self, row, metadata=None):
    	        return TvShow(title=row[0],
    	                      airDate=row[1],
    	                      episodeNumber=row[2],
    	                      writer=row[3])
  5. With all this setup, we can now create an instance of DatabaseTemplate and use it to execute the same query with a much lower footprint.

    	dt = DatabaseTemplate(connectionFactory)
    
    	"""Repeated for each query"""
    	results = dt.query("""select title, air_date, episode_number, writer from tv_shows where name = %s""",
                         ("Monty Python",), TvShowMapper())

This example shows how we can replace 19 lines of code with a single statement using Spring Python's template solution.

Object Relational Mappers (ORMs) have sprung up in response to the low level nature of ANSI SQL's protocol. Many applications have simple object persistence requirements and many of us would prefer working on code, and not database design. By having a tool to help do the schema management work, these ORMs have been a great productivity boost.

But they are not necessarily the answer for every use case. Some queries are very complex and involve looking up information spread between many tables, or involve making complex calculations and involve decoding specific values. Also, many legacy systems are denormalized and don't fit the paradigm that ORMs were originally designed to handle. The complexity of these queries can require working around, or even against, the ORM-based solutions, making them not worth the effort.

To alleviate the frustration of working with SQL, Spring Python's DatabaseTemplate greatly simplifies writing SQL, while giving you complete freedom in mapping the results into objects, dictionaries, and tuples. DatabaseTemplate can easily augment your application, whether or not you are already using an ORM. That way, simple object persistence can be managed with ORM, while complex queries can be handed over to Spring Python's DatabaseTemplate, resulting in a nice blend of productive, functional code.

Other templates, such as TransactionTemplate, relieve you of the burden of dealing with the low level idioms needed to code transactions that makes them challenging to incorporate correctly. Later in this book, we will learn how easy it is to add transactions to our code both programmatically and declaratively.

Applying the services you need and abstracting away low level APIs is a key part of the Spring way and lets us focus our time and effort on our customer's business requirements instead of our own technical ones.

By using the various components we just looked at, it isn't too hard to develop a simple Pyro service that serves up TV shows from a relational database.

from springpython.database.factory import *
from springpython.config import *
from springpython.remoting.pyro import *
        
class TvShowMapper(RowMapper):
    def map_row(self, row, metadata=None):
        return (title=row[0],
                      airDate=row[1],
                      episodeNumber=row[2], 
                      writer=row[3])

class TvShowService(object):
    def __init__(self):
        self.connFactory = MySQLConnectionFactory(username="me",
                                                  password="secret",
                                                hostname="localhost",
                                                  db="springpython")
        self.dt = DatabaseTemplate(connFactory)

    def get_tv_shows(self):
        return dt.query("""select title, air_date, episode_number, writer
                           from tv_shows where name = %s""",
                           ("Monty Python",), TvShowMapper())
class TvShowContainer(PythonConfig):
    def __init__(self):
        super(TvShowContainer, self).__init__()

    @Object(lazy_init=True)
    def web_server(self):
        return PyroServiceExporter(service=TvShowService(),
                                   service_name="tvshows",
                                   service_port=9000)

    @Object(lazy_init=True)
    def web_client(self):
        myService = PyroProxyFactory()
        myService.service_url="PYROLOC://localhost:9000/tvshows"
        return myService

if __name__ == "__main__":
    container = ApplicationContext(TvShowContainer())
    container.get_object("web_server")

By querying the database for TV shows and serving it up through Pyro, this block of code demonstrates how easy it is to use these powerful modules without mixing them together. It is much easier to maintain software over time when things are kept simple and separated.

We just took a quick walk through SQL and Pyro and examined their low level APIs. Many low level APIs require a certain sequence of steps to properly utilize them. We just looked at a SQL query. The need for templates also exists with database transactions and LDAP calls. By capturing the flow of the API in a Spring Python template and allowing you to insert your custom code, you can get out of writing plumbing code and instead work on your application's business logic.

 

Spring Python for Java developers


Java developers often seek ways to increase productivity. With the incredible growth of alternative languages on the Java Virtual Machine (JVM), it is no wonder developers are looking into Jython (http://www.jython.org) as an alternative way to write scripts, segments, and subsystems. While it's convenient to use the Java libraries you already know, it can sometimes be rough interacting with the Java idioms of the library.

Spring Python is written in pure Python, which makes it easy to use inside Jython as well. You may find it easier and more appealing to utilize the pythonic APIs of Spring Python rather than the Java idioms of the Spring Framework. The choice ultimately is yours, and it's not an either/or decision; you can use both libraries in both your Java and Python segments.

The following diagram shows a combination of Python, Jython, and pure Java as a stack.

With Spring Python, it's easy to mix Java and Python together. Let's code a simple example, where we write a Jython client that talks to the TV service shown in the previous section. By reusing that code, we can easily code a client. To really show the power of Python/Jython/Java integration, let's expose our Jython client to a pure Java consumer.

  1. To begin, we need a pure Java interface that our Jython code can extend.

      import org.python.core.PyList;
    
        public interface JavaTvShowService {
    
          public PyList getTvShows();
    
      }
  2. Next, we write our Jython class to extend this interface.

      class JythonTvShowService(JavaTvShowService):
          def __init__(self):
              self.container = ApplicationContext(TvShowContainer())
              self.client = container.get_object("web_client")
            
          def getTvShows(self):
              return self.client.get_tv_shows()	
  3. For Java clients to call Jython, we need to create a factory that creates an embedded Jython interpreter.

      import org.python.core.PyObject;
      import org.python.util.PythonInterpreter;
    
      public class TvShowServiceFactory {
    
        private PyObject clazz;
    
        public TvShowServiceFactory() {
              PythonInterpreter interp  = new PythonInterpreter();
              interp.exec("import JythonTvShowService");
              clazz = interp.get("JythonTvShowService");
      }
        public JavaTvShowService createTvShowService() {
          PyObject tvShowService = clazz.__call__();
          return (JavaTvShowService)
          tvShowService.__tojava__(JavaTvShowService.class);
        }
      }
  4. Finally, we can write a main function that invokes the factory first, and then the JavaTvShowService.

      public class Main {
    
        public static void main(String[] args) {
          TvShowServiceFactory factory = 
                          new TvShowServiceFactory(); 
          JavaTvShowService service =
                        factory.createTvShowService();
          PyList tvShows = service.getTvShows();	
          for (int i = 0; i < tvShows.__len__(); i++) {
            PyObject obj = tvShows.__getitem__(i);
            PyTuple tvShow =
                   (PyTuple)obj.__tojava__(PyTuple.class);
            System.out.println("Tv show title=" + tvShow.get(0) +
                               " airDate=" + tvShow.get(1) +
                               " episode=" + tvShow.get(2) +
                               " writer=" + tvShow.get(3));
          }
        }
      }

We defined an interface, providing a good boundary to code both Java consumers and Jython services against. Our Jython class extends the interface and when created, creates an IoC container which requests a web_client object. This is our PyroProxyFactory that uses Pyro to call our pure Python service over the wire. By implementing the interface, we conveniently expose our remote procedure call to the Java consumers. Our Java app needs a factory class to create a Jython interpreter which in turn creates an instance of our Jython class. We use this in our application main to get an instance of our TV service. Using the service, we call the exposed method which makes our Pyro remote call. We iterate over the received list and extract a tuple in order to print out results.

After taking a glance at how to expose a pure Python service to a pure Java consumer, the options from here are endless. We could use Spring Java's RmiServiceExporter or HessianServiceExporter to expose our Python service to other protocols. This service could be integrated into a Spring Integration workflow or made part of a Spring Batch job. There really is no limit. We will explore this in more detail in Chapter 10 with our case study.

We have already looked at how easy it is to expose Python services to Java consumers. If you are already familiar with Spring Java, hopefully as you read this book, you will notice that the Spring way works not only in Java but in Python as well. Spring Python uses the same concepts as Spring Java, shares some class names with Spring Java, and even has an XML parser that can read Spring Java's format. All of these things increase the ability to rewrite some parts in Python while making small changes in the configuration files. All of these aspects make it easier to incrementally move our application to the sweet spot we need for improved productivity.

 

Extending Spring Python


Spring Python provides easy access to services, libraries, and APIs through its neatly segmented set of modules. Spring Python's flexibility is due to its modular nature. Providing you with a small set of blocks that are easy to combine is much more reusable than a monolithic set of classes to extend. These techniques open the door to easily integrating with current technologies and future ones as well.

In this chapter, we have already looked at various features, including remoting, DatabaseTemplate, and integrating Python with Java. As we explore the other features of Spring Python, I hope you can realize that using the Spring way of writing useful abstractions and delegating object creation to the Spring Python container makes it easy to write more modules that aren't part of this project yet.

And as your needs grow, this project will grow as well. Spring Python makes it easy to code your own templates and modules. You can code and inject your custom services just as easily as Spring Python's pre-built ones. If you have ideas for new features that you think belong in Spring Python, you can visit the website at http://springpython.webfactional.com to find out how to submit ideas, patches, and perhaps join the team to help grow Spring Python.

 

Installing Spring Python


Spring Python is easy to install. It comes with two installable tar balls. One is the core library itself. The other is a set of samples you can optionally install to help get a better understanding of Spring Python. As it is written in pure Python, the installed files are the source code as well, so you can see how Spring Python works.

Note

This installation section does NOT show how to install all the parts needed to develop patches for the Spring Python project. For more information on setting up a developer's environment, please join the Spring Python mailing list at http://lists.springsource.com/listmanager/listinfo/springpython-users where you can ask about current development requirements.

Setting up an environment for Spring Python

Installing Spring Python currently requires Python 2.4, 2.5, or 2.6. It can also be run on Jython 2.5. At the time of this writing, it hasn't been extended to support Python 3 due to lack of backwards compatibility and immaturity. However, as Python 3 gains acceptance in the user community, Spring Python will move to support it as well.


Spring Python makes it easier to integrate with certain 3rd party libraries. Installation of those 3rd party libraries is not covered in this book. For example, to write queries against an Oracle database, you need to install the cxora package.

Installing from a pre-built binary download

The binaries are hosted as tar balls by SpringSource, in the community section. They are non-OS specific and should work on any platform.

  1. Go to http://www.springsource.org/download/community. You can either fill out the registration information, or simply click on the link to take you to the download site

  2. Click on Spring Python to see the latest version:

  3. Download springpython-<release>.tar.gz to get the core library

  4. Unpack the tarball, and go to the directory containing setup.py

  5. Type the following command to install Spring Python

    Note

    This step may require admin privileges!

    $ python setup.py install
    
  6. You should now be able to test the installation.

    $ python
    >>> import springpython
    >>> dir()
    ['__builtins__', '__doc__', '__name__', 'springpython']

Installing from source

Spring Python can be installed from source code like many other open source projects. The code is hosted on a subversion repository. The following steps will help you download the code and install it on your machine:

  1. Type the following command to checkout the latest trunk repository:

    $ svn checkout https://src.springframework.org/svn/se-springpython-py/trunk/springpython springpython

    This will create a local directory springpython containing the latest changes.

  2. Move in to the directory where build.py is located. This script serves as the key tool to build, package, and test Spring Python. Type the following command to generate an installable Spring Python package:

    $ ./build.py –package
  3. Move to target/artifacts, the directory containing the newly generated tar balls.

  4. Unpack the tar ball springpython-<release>.tar.gz, and go to the directory containing setup.py and type the following command to install Spring Python:

    Note

    Note: This step may require admin privileges.

    $ python setup.py install
    
  5. You should now be able to test the installation.

    $ python
    >>> import springpython
    >>> dir()
    ['__builtins__', '__doc__', '__name__', 'springpython']
  6. Using the subversion repository to fetch source code sets you up to easily install new updates.

  7. Type the following command to update your checkout.

    $ svn update /path/for/springpython
  8. Repeat the steps with build.py, target/artifacts, and setup.py.

    Tip

    Official releases are found in the tags section of the subversion repository, adjacent to the trunk.

Note

You can also visually inspect the code using SpringSource's Fisheye viewer at https://fisheye.springframework.org/browse/se-springpython-py. This provides a way to view the code, change sets, and change logs as well.

 

Spring Python community


Spring Python values its user community, and takes its cue on key features from user requests. Many of the features currently found in Spring Python were added based on user requests, submitted patches, and feedback.

 

Summary


We have taken a quick tour of the various parts of Spring Python. The examples showed examples of how Spring Python can make things easier for both Python and Java developers.

In this chapter, we learned that:

  • Spring Python has a non-invasive API that makes it easy to use other libraries without having to make major changes to your own code base

  • Spring Python has a container that decouples object creation from object usage to empower the developer

  • Spring Python provides the means to help professional Python developers by offering a non-invasive API to easily access advanced services

  • Spring Python offers professional Java developers an easy way to mix Python and Java together through the combination of Python/Jython/Java

  • Spring Python can be installed from both binary and source code

  • Spring Python is very extensible and easily lets us add new components

  • There is a user community where we can post questions, answers, ideas, and patches

In the next chapter, we will go deep into the heart of Spring Python with its Inversion of Control container.

About the Author

  • Greg L. Turnquist

    Greg L. Turnquist has been a software professional since 1997. In 2002, he joined the senior software team that worked on Harris' $3.5 billion FAA telco program, architecting mission-critical enterprise apps while managing a software team. He provided after-hours support to a nation-wide system and is no stranger to midnight failures and software triages. In 2010, he joined the SpringSource division of VMware, which was spun off into Pivotal in 2013.

    As a test-bitten script junky, Java geek, and JavaScript Padawan, he is a member of the Spring Data team and the lead for Spring Session MongoDB. He has made key contributions to Spring Boot, Spring HATEOAS, and Spring Data REST while also serving as editor-at-large for Spring's Getting Started Guides.

    Greg wrote technical best sellers Python Testing Cookbook and Learning Spring Boot, First Edition, for Packt Publishing. When he isn't slinging code, Greg enters the world of magic and cross swords, having written the speculative fiction action and adventure novel, Darklight.

    He completed his Master's degree in computer engineering at Auburn University and lives in the United States with his family.

    Browse publications by this author