Archive

Posts Tagged ‘Spring Python’

Zato 1.0. The next generation ESB and application server. Open-source. In Python.

May 18th, 2013 No comments

(This is a re-post of what I sent to python-announce@ but with several screenshots attached)

I’m very happy to announce the first release of Zato, the next generation ESB and application server, available under a commercial-friendly open-source LGPL license.

https://zato.io

What can you expect out of the box?

  • HTTP, JSON, SOAP, Redis, AMQP, JMS WebSphere MQ, ZeroMQ, FTP, SQL, hot-deployment, job scheduling, statistics, high-availability load balancing and more
  • Incredible productivity with Python
  • Painless rollouts with less downtime
  • Slick web admin GUI, CLI and API
  • Awesome documentation (several hundred A4 pages)
  • 24×7 commercial support and training

Project’s site: https://zato.io
Download: https://zato.io/download/zato-1.0.tar.bz2
Support: https://zato.io/support
Docs: https://zato.io/docs
Architecture: https://zato.io/docs/architecture/overview.html
Tutorial: https://zato.io/docs/tutorial/01.html
GitHub: https://github.com/zatosource
Mailing list: https://mailman-mail5.webfaction.com/listinfo/zato-discuss
IRC: irc://irc.freenode.net/zato
Twitter: https://twitter.com/zatosource
LinkedIn: https://www.linkedin.com/groups?gid=5015554
Diversity statement: https://zato.io/docs/project/diversity.html

Spread the news and enjoy :-)

Cheers!

 

 

 

 

 

 

 

@fourthrealm

Share

JMS Messaging with Spring Python and WebSphere MQ (did you know about it?)

August 20th, 2012 Comments off

Did you know you could easily exchange JMS messages using Spring Python and WebSphere MQ? This all being completely transparent to the other side of course. No one will know it’s a Python application speaking this end though truth to be told, maybe it’s high time all the bloated stacks should be done away with and more people started using smarter tools? :?

In any case, is there an interest in my writing more about it in addition to the comprehensive documentation available over at the project’s site?

# -*- coding: utf-8 -*-
 
from springpython.jms.core import JmsTemplate
from springpython.jms.factory import WebSphereMQConnectionFactory
 
qm_name = 'QM01'
channel = 'SVRCONN.1'
host = '127.0.0.1'
listener_port = '1434'
queue1 = 'TEST.1'
 
# The connection factory we're going to use
factory = WebSphereMQConnectionFactory(qm_name, channel, host, listener_port)
 
# Every JmsTemplate uses a connection factory for actually communicating with a JMS provider
jms_template = JmsTemplate(factory)
 
# And that's it, now we put the mandatory 'Hello world' message on a queue
jms_template.send('Hello world', queue1)
 
# We're not using an Inversion of Control container so we must shut the connection factory down ourselves
factory.destroy()

@fourthrealm

Share

Installing sec-wall on Debian wheezy/sid

June 13th, 2011 Comments off

The unstoppable Miguel Landaeta did it again and I’m happy to let you all know that sec-wall, the security proxy, can be now installed on Debian wheezy/sid using nothing but DEBs, like below. The only prerequisite is that you need to visit http://alioth.debian.org/~nomadium-guest/debian/unstable/ to find and download the latest DEB – at the time of this writing it’s sec-wall_1.0.0-0miguel2_all.deb but it sure is going to change shortly because sec-wall 1.1 is about to be released soon.

First, the dependencies:

apt-get install python-springpython python-gevent
apt-get install python-argparse python-lxml
apt-get install python-pesto python-zdaemon
apt-get install python-pkg-resources

Now install sec-wall:

dpkg -i ./sec-wall_1.0.0-0miguel2_all.deb

And that’s all! :-)

@fourthrealm

Share

Announcing sec-wall 1.0.0, a feature packed high-performance security proxy

April 8th, 2011 Comments off

This is mostly a copy of the announcement sent to the python-announce@ list, although I’ve added a couple more usage examples at the end of the post.

sec-wall is a feature packed high-performance security proxy which has many interesting features, including the support for SSL/TLS, WS-Security, HTTP Auth Basic/Digest, extensible authentication schemes based on custom HTTP headers and XPath expressions, powerful URL matching/rewriting and an optional headers enrichment.

sec-wall uses and is built on top of several fantastic Python open source technologies, such as gevent, Spring Python, Pesto, lxml, zdaemon or PyYAML and is meant to be highly customizable and easy to use. Good performance, tests, documentation and building an awesome community are at the very heart of the project.

Here are  examples showing how little is needed to secure a backend server with HTTP Basic Auth, SSL/TLS client certificates and WS-Security.

# -*- coding: utf-8 -*-
 
# stdlib
import uuid
 
# Don't share it with anyone.
INSTANCE_SECRET = '5bf4e78c256746eda2ce3e0e73f256d0'
 
# May be shared with the outside world.
INSTANCE_UNIQUE = uuid.uuid4().hex
 
def default():
    return {
        'basic-auth':True,
        'basic-auth-username':'MyUser',
        'basic-auth-password':'MySecret',
        'basic-auth-realm':'Secure area',
        'host': 'http://example.com'
    }
 
urls = [
    ('/*', default()),
]

# -*- coding: utf-8 -*-
 
# stdlib
import os.path as path, uuid
 
# Don't share it with anyone.
INSTANCE_SECRET = '5bf4e78c256746eda2ce3e0e73f256d0'
 
# May be shared with the outside world.
INSTANCE_UNIQUE = uuid.uuid4().hex
 
# Useful constants
cur_dir = path.dirname(__file__)
 
# Crypto
keyfile = path.join(cur_dir, './crypto/server-priv.pem')
certfile = path.join(cur_dir, './crypto/server-cert.pem')
ca_certs = path.join(cur_dir, './crypto/ca-cert.pem')
 
server_type = 'https'
 
def default():
    return {
        'ssl': True,
        'ssl-cert': True,
        'ssl-cert-commonName': 'My Client',
        'ssl-cert-organizationName': 'My Company',
        'host': 'http://example.com'
    }
 
urls = [
    ('/*', default()),
]

# -*- coding: utf-8 -*-
 
# stdlib
import uuid
 
# Don't share it with anyone.
INSTANCE_SECRET = '5bf4e78c256746eda2ce3e0e73f256d0'
 
# May be shared with the outside world.
INSTANCE_UNIQUE = uuid.uuid4().hex
 
def default():
    return {
        'wsse-pwd': True,
        'wsse-pwd-username': 'MyUser',
        'wsse-pwd-password': 'MySecret', # Needs to be given in clear text
        'wsse-pwd-reject-empty-nonce-creation': True,
        'wsse-pwd-reject-stale-tokens': True,
        'wsse-pwd-reject-expiry-limit': 120,
        'wsse-pwd-nonce-freshness-time': 120,
        'host': 'http://example.com'
    }
 
urls = [
    ('/*', default()),
]

Links:

Project’s homepage: http://sec-wall.gefira.pl/
Getting started: http://sec-wall.gefira.pl/documentation/getting-started/index.html
Usage examples: http://sec-wall.gefira.pl/documentation/usage-examples/index.html
Twitter: https://twitter.com/fourthrealm
Blog: http://www.gefira.pl/blog
IRC: #sec-wall channel on Freenode network

Cheers!

@fourthrealm

Share

Spring Python 1.2 & SSL/TLS XML-RPC (a friendly reminder)

February 20th, 2011 Comments off

Spring Python 1.2 has been released some time ago and one of its newest features is the support for wrapping XML-RPC with SSL/TLS, including both clients and servers. I’ve covered it already in a tutorial some time ago but I don’t think Planet Python was picking up the blog’s posts at that time, besides, Spring Python was still a release candidate when I was writing it so things could’ve changed (but they didn’t :-) ). In any case, now that 1.2 is a stable release, I thought I’d just mention it in case you were looking for means to secure your XML-RPC traffic. Here’s the reference material and the tutorial is here.

@fourthrealm

Share

HOWTO: Installing Spring Python and its dependencies

December 17th, 2010 Comments off

Depending on your exact needs and the work environment, there are several ways to install Spring Python with its dependencies and this post will go through what’s available.

First thing is, install pip, this is the command line tool to use for installing Python software.

Here are the installation options:

  1. Telling pip to fetch it from PyPI and then install it, type:
    • pip install springpython, this will download the latest version – currently it’s 1.2.0RC1 – from the remote repository and install it
  2. Downloading the source installer from the Spring Source site manually – the link always points to the latest release of Spring Python though you can also pick from any previous releases. At the time of this writing, the latest release is springpython-1.2.0.RC1.tar.gz, place it in any directory and type pip install springpython-1.2.0.RC1.tar.gz to install it.
  3. Using the latest git version (read only) – create a directory, cd to it and type:
    • git clone git://git.springsource.org/spring-python/spring-python.git, this will create a local clone of the latest version of the source code
    • cd spring-python
    • python build.py –package, note the name of a tar.gz package that will be created, in my case it was springpython-1.3.0.BUILD-20101216115817
    • pip install target/artifacts/springpython-1.3.0.BUILD-20101216115817.tar.gz to install the newly built package
  4. Using the latest git version (read/write, for core developers) – same as the previous point except for the first command, its should be git clone git@git.springsource.org:spring-python/spring-python.git, note that the command is very similar to the previous one and for me personally it used to be a source of confusion, but that I guess is a git thing.
  5. Using the DEB installer created by Sven Wilhelm and Miguel Landaeta
    • Add deb http://ppa.wiredobjects.eu/springpython/ppa/debian experimental main to /etc/apt/sources.list
    • Issue sudo apt-get update && apt-get sudo install python-springpython to refresh the sources list and install Spring Python
    • Note there’s ‘debian’ in the name but I’ve had no problems with using the DEB on Ubuntu 10.04

A word on the project’s dependencies. The commands above will install Spring Python but it still doesn’t mean you’ll be able to make use of each and every piece of functionality. The installation methods mentioned above haven’t been (yet) broken into smaller ones, each of which could express its own concrete dependencies and on the other hand, adding a huge list of mandatory dependencies would clearly be an overkill, after all, not every project needs to access XML, Yaml, Oracle, Postgres, JMS WebSphere MQ, Pyro, Hessian, CherryPy and other external resources at the same time :-) So, once you install Spring Python, you still need to check the documentation for a list of things to install before you can start using a given Spring Python’s feature. Each chapter has a section devoted to listing all the dependencies or stating that a stock Python distribution will do, see for instance Security, AOP, IoC, JMS and Remoting.

I hope it sheds some light on the matter, in case you need any help, be sure to drop in the forum, mailing list or the IRC channel (#springpython on Freenode network). See you!

@fourthrealm

Share

Securing XML-RPC with Spring Python and SSL/TLS

November 5th, 2010 Comments off

One of the new features in Spring Python 1.2 is the support for wrapping the XML-RPC conversations in SSL/TLS, sporting plain encryption of communications as well as advanced tricks such as configuring the server to validate the particular values of a client’s certificate. There’s already a good deal of documentation available at the project’s website and in addition to that this article will guide you through the process of setting things up and configuring both secure clients and servers.

Note that I’m using Linux but it’s simply a matter of personal preferences, things will work as well on Windows, Solaris, AIX or any other system. It’s all pure Python with no C modules underneath.

Let’s go ahead and use pip to install Spring Python:

$ sudo pip install springpython

The command above will contact PyPI and fetch the latest release of Spring Python, which at the time of this writing is 1.2.0.RC1.

What will also come handy is the bundle of sample certificates and keys the Spring Python team has prepared for people learning the API, so let’s download it now

$ wget -c http://springpython.webfactional.com/1.2.x/sphinx/html/_static/pki.zip

The archive contains crypto material for a simple PKI, two CAs and two end users of the certificates – an XML-RPC server and its client. Take a look at the diagram at the project’s site which depicts closely whose certificate has been signed off by whom and who to trust in this PKI. There’s plenty of time for playing around with the API, the certificates will not expire until 2020.

A word of caution – the ZIP archive you’ve just downloaded contains the private keys and that basically renders it unsuitable for any use outside your development box, in real life scenarios you need to make sure you use certificates signed off by your company’s CA(s), or by a CA of your own; just make sure you’re not using the samples for anything close to production environments.

OK, let’s create a first client/server pair, one which will simply have the link encrypted and which will also make sure the certificates have been signed off by a known CA. The client sure has to authenticate itself to the server and in this simple case it will be using a username/password combination.

Client code:

# -*- coding: utf-8 -*-
 
# Spring Python
from springpython.remoting.xmlrpc import SSLClient
 
server_location = "https://localhost:8000/RPC2"
ca_certs = "./ca-chain.pem"
 
client = SSLClient(server_location, ca_certs)
print client.get_randint("user", "password")

Server code:

# -*- coding: utf-8 -*-
 
# stdlib
import random, ssl, sys
 
# Spring Python
from springpython.remoting.xmlrpc import SSLServer
 
random.seed()
 
class MySSLServer(SSLServer):
 
    security_db = {"user": "password"}
 
    def get_randint(self, username, password):
        if self.security_db.get(username, "") == password:
            return random.randint(0, 1000)
 
        raise Exception("I don't know you!")
 
    def register_functions(self):
        self.register_function(self.get_randint)
 
host = "localhost"
port = 8000
keyfile = "./server-key.pem"
certfile = "./server-cert.pem"
ca_certs = "./ca-chain.pem"
 
server = MySSLServer(host, port, keyfile, certfile, ca_certs,
                  cert_reqs=ssl.CERT_OPTIONAL)
server.serve_forever()

Client doesn’t need anything except for the file (ca_certs) containing a list of CAs it is willing to trust, that is, the server’s certificate will be accepted by the client only if it’s been signed off by a CA whose certificate is in this file. The file may contain an unlimited number of certificates, including chains of certificates.

The server code is a tad more complex but only a little bit. In addition to “ca_certs” parameter which has exactly the same purpose as it had on the client end, the server needs to have its own certificate and a private key. On the business-level side of things, you can notice that just like in the stdlib, you’re using self.register_function for exposing methods over the wire. Oh, and make a mental note that the server’s cert_reqs parameters is ssl.CERT_OPTIONAL. What it means is that we don’t really care whether client sends us any certificate, it may do so but that’s no big deal if it doesn’t.

So that’s how things could possibly stay if it weren’t for the authentication. I don’t know about you but I personally can’t stand the fact that a business method (get_randint) has been tasked with checking the client’s credentials. It could be worked around in several ways but for the sake of this article we’re going to make client application use its (drumroll..)  client certificate! It makes sense to use one because we already have a PKI and the server’s using its own certificate. While we’ll be at making the client use a certificate, we’ll also tell the server to let the client in only if a given set of fields in the client certificate matches the server’s configuration. To be precise – we’ll make sure that the client cert’s commonName is equal to My Client and organizationName is My Company. It follows that we’ll change the cert_reqs value to ssl.CERT_REQUIRED at the same time.

Here’s the code for the client:

# -*- coding: utf-8 -*-
 
# Spring Python
from springpython.remoting.xmlrpc import SSLClient
 
server_location = "https://localhost:8000/RPC2"
keyfile = "./client-key.pem"
certfile = "./client-cert.pem"
ca_certs = "./ca-chain.pem"
 
client = SSLClient(server_location, ca_certs, keyfile, certfile)
print client.get_randint()

.. and the server:

# -*- coding: utf-8 -*-
 
# stdlib
import random, ssl
 
# Spring Python
from springpython.remoting.xmlrpc import SSLServer
 
random.seed()
 
class MySSLServer(SSLServer):
 
    def get_randint(self):
        return random.randint(0, 1000)
 
    def register_functions(self):
        self.register_function(self.get_randint)
 
host = "localhost"
port = 8000
keyfile = "./server-key.pem"
certfile = "./server-cert.pem"
ca_certs = "./ca-chain.pem"
verify_fields = {"commonName": "My Client", "organizationName":"My Company"}
 
server = MySSLServer(host, port, keyfile, certfile, ca_certs,
                  cert_reqs=ssl.CERT_REQUIRED, verify_fields=verify_fields)
server.serve_forever()

And that’s all there is to it, at least in this case. The server concerns itself with, well, services only, the link is encrypted, the client is being authenticated and everyone’s happy :-) These aren’t all the options you can use but the rest is there, in the project’s documentation so go have a read if you need more customization. And in case you have any questions, need help or just want to chat, be sure to drop by on IRC (#springpython@Freenode), visit the project’s forum or the mailing list. Cheers!

@fourthrealm

Share

Spring Python 1.1 book review

August 22nd, 2010 Comments off

Here’s a copy of my Amazon’s Spring Python 1.1 book review.

Spring Python 1.1 is a book for professional programmers who either wish to venture into a world beyond traditional OOP and tackle problems differently thanks to Spring Python’s IoC & AOP features or simply have practical issues – such as spreading the application across multiple nodes – to solve. The book does not merely rephrase the comprehensive reference documentation available at the project’s website and I was actually very curious on how the author would be laying out the material.

Greg took a very good approach of explaining the basic of IoC first and building upon it in subsequent chapters although they can all be read separately. All of the major Spring Python’s building blocks are covered and I can only applaud that despite its Java roots almost no XML is used – that’s a good news for all Python programmers fearing that “Spring” means a lot of unnecessary XML, the prevailing majority of examples is in pure Python. Java programmers wishing to leverage their existing Spring skills won’t be disappointed though as there are some chapters devoted to how one can easily migrate a Spring Java IoC container over to Spring Python one, there’s also a discussion of how to use Spring Python & Jython which, along with CPython, is also a target Python implementation Spring Python can run on. But let that not confuse you, the book is mostly written for Python programmers.

I liked it that the book was focusing on getting things done without turning aside into discussing vaguely related concepts or nuances, for instance the chapter on SQL doesn’t do any ‘quick recaps’ of what SQL and relational databases are as is unfortunately quite common in many other books. On the other hand, not everyone is familiar with IoC and AOP and I know that anyone unfamiliar with those concepts – regardless of their primary programming language of choice – can easily take the book and get acquainted with them. A superb idea was that most of the chapters teach you how to write unit tests for the given Spring Python component you’d want to use in your code, IoC, AOP, security, database access and so on, that’s an often neglected area and I was very happy to see the author having placed an importance on it. Another good idea was to create a case-study chapter which combines all the knowledge and discusses it thoroughly.

All in all, it’s a good book written by a practitioner for practitioners, full of diagrams and examples that by necessity are simple yet don’t feel contrived and it’s certainly not something you need to plough through, it does a very good job of introducing the reader to Spring Python and showing how to use its pluggable components to write interesting and useful applications solving real-world problems. If I were to pick a nit I’d only say that it would be nice if the second edition contained at least a couple of examples of using Spring Python’s IoC YamlConfig, but that’s only a matter of syntax so the issue is really minor.

@fourthrealm

Share
Categories: Software Tags: ,

Intro To Spring Python Slides

June 3rd, 2010 No comments

For those of you who are still wavering over whether to use Spring Python in your next project, have a look at this slidecast describing the current Spring Python project’s status, as of release 1.1, and where it’s heading to.

@fourthrealm

Share
Categories: Software Tags:

An introduction to Spring Python and IoC/DI (Inversion of Control/Dependency Injection)

May 1st, 2010 Comments off

Continuing on the last post, we’ll now be extending the code with an IoC (Inversion of Control)-driven configuration. Spring Python offers an IoC container which may be used for injecting dependencies between the application’s objects. The concept is that objects are to focus on their job and usually should be blissfully unaware of where the other objects they operate upon come from. The dependencies are dynamically injected so the control of who uses what is sort of inverted, it’s the container who knows what and when to distribute to others in order for everything to play nicely together and that’s why language lawyers can’t decide whether to call it IoC (Inversion of Control) or DI (Dependency Injection) but let that not stop us from applying it in practice :-) And of course it’s only a concept, it’s not something magical, it’s simply a decent addition to your toolbox which you may like to get familiar with and Spring Python with its gentle learning curve is just the right tool. Throughout the article, Spring Python 1.1 will be used.

Picking off from where we left last time, here’s a bare bones ‘uptime’ server and its client.

# An 'uptime' server
 
# stdlib
import logging
import commands
 
# Spring Python
from springpython.remoting.pyro import PyroServiceExporter
 
# Configure logging subsystem
logging.basicConfig(level=logging.DEBUG)
 
class Service(object):
    def get_uptime(self):
        logging.info("get_uptime invoked")
        return commands.getoutput("uptime")
 
# Create a service ..
service = Service()
 
# .. export it through Pyro ..
service_exporter = PyroServiceExporter()
service_exporter.service = service
service_exporter.service_name = "Service"
service_exporter.service_host = "127.0.0.1"
service_exporter.service_port = "16099"
 
# .. and start the server.
service_exporter.after_properties_set()
# Client
 
# stdlib
import logging
 
# Spring Python
from springpython.remoting.pyro import PyroProxyFactory
 
# Configure logging subsystem
logging.basicConfig(level=logging.DEBUG)
 
# Point the client to a server ..
service = PyroProxyFactory()
service.service_url = "PYROLOC://127.0.0.1:16099/Service"
 
# .. invoke the service ..
uptime = service.get_uptime()
 
# and print it on the console.
logging.info("Current uptime: [%s]" % uptime)

A word on Spring Python’s IoC syntax, there’s a plenty of choices to pick from, with three major ones being PythonConfig, YamlConfig and XMLConfig. Being agile Python folks as we are, we chose to use YamlConfig and PythonConfig for configuring things but it should be noted that all other config modes would’ve allowed us to achieve the same.

As always, it’s all up to you to decide what makes more sense in given circumstances though my recommendation is to use YamlConfig or XMLConfig with a strong preference on the former if you work in a diverse Python/Java/.NET environment with people who already know Spring Framework and PythonConfig/YamlConfig if you’re free to choose whatever you like.

So here’s the server’s basic configuration written in YAML..

# server-config.yml
 
objects:
    - object: service_name
      str: Service
 
    - object: service_host
      str: 127.0.0.1
 
    - object: service_port
      str: 16099

.. and here’s some code to read if off a file we stored it in:

# ioc-yaml-sample.py
 
# Spring Python
from springpython.config import YamlConfig
from springpython.context import ApplicationContext
 
config = YamlConfig("./server-config.yml")
container = ApplicationContext(config)
 
service_name = container.get_object("service_name")
print "Hey, the name is '%s'" % service_name

YamlConfig’s instance reads the file, parses it, creates an internal cache of definitions found and then the config may be fed to ApplicationContext which is the actual class used for fetching objects from a container. Why is the class called ApplicationContext instead of Container, you wonder? Well in fact the actual container is called springpython.container.ObjectContainer and ApplicationContext subclasses it in order to add some additional goodies such as the possibility of hooking into an object’s lifecycle.

Let’s now introduce server to the config and let’s create the main application’s module, boringly named ‘main.py’, so that in result we have following files ..

.
|-- client.py
|-- main.py
|-- server-config.yml
`-- server.py

.. with such a contents ..

# client.py (no changes here so far)
 
# stdlib
import logging
 
# Spring Python
from springpython.remoting.pyro import PyroProxyFactory
 
# Configure logging subsystem
logging.basicConfig(level=logging.DEBUG)
 
# Point the client to a server ..
service = PyroProxyFactory()
service.service_url = "PYROLOC://127.0.0.1:16099/Service"
 
# .. invoke the service ..
uptime = service.get_uptime()
 
# and print it on the console.
logging.info("Current uptime: [%s]" % uptime)
# main.py
 
# stdlib
import logging
 
# Spring Python
from springpython.config import YamlConfig
from springpython.context import ApplicationContext
 
config = YamlConfig("./server-config.yml")
container = ApplicationContext(config)
 
# Fetch configuration from the container ..
log_level = container.get_object("log_level")
log_format = container.get_object("log_format")
 
# .. and configure logging.
logger = logging.getLogger("")
logger.setLevel(logging.getLevelName(log_level))
 
handler = logging.StreamHandler()
 
formatter = logging.Formatter(log_format)
handler.setFormatter(formatter)
 
logger.addHandler(handler)
# server-config.yml
 
objects:
    - object: service_name
      str: Service
 
    - object: service_host
      str: 127.0.0.1
 
    - object: service_port
      str: 16099
 
    - object: service
      class: server.Service
 
    - object: exporter
      class: springpython.remoting.pyro.PyroServiceExporter
      properties:
        service: {ref: service}
        service_name: {ref: service_name}
        service_host: {ref: service_host}
        service_port: {ref: service_port}
 
    - object: log_level
      str: DEBUG
 
    - object: log_format
      str: "%(asctime)s - %(levelname)s - %(process)d:%(threadName)s - %(name)s:%(lineno)d - %(message)s"
# server.py
 
# stdlib
import logging
import commands
 
class Service(object):
    def __init__(self):
        self.logger = logging.getLogger("%s:%s" % (__name__, self.__class__.__name__))
 
    def get_uptime(self):
        self.logger.info("get_uptime invoked")
        return commands.getoutput("uptime")

So what have we achieved? The actual business logic has been decoupled from its configuration so that it doesn’t know anything about Pyro because, after all, should it care about it? Its business is to return the current uptime and that’s what it’s good at. That it’s going to be exposed through Pyro is also not that important for its core functionality, it’s Pyro today but could be Zope tomorrow, who knows it. PyroServiceExporter also happily lives in a state of not really being aware of what service it is publishing outside. Changing either of those should not mean touching the source code even if it meant merely adding a couple of lines of code. And the other stuff, it’s just a simple configuration we had to externalize anyway so why not put it into same place for consistency? To keep things simpler, the client code hasn’t been changed yet though it will be later on when we’ll be working with PythonConfig.

When choosing what to place in the container there’s always a danger of going too far and letting it all look awkwardly and unpythonic or just plain ugly. As a rule of thumb, your application surely can be explained in terms of some kind of components which need to be wired up together and that’s where the division line could be initially drawn. Another point is standard configuration details such as host, port or the logging format above, it’s something that sysadmins love to customize so it should allow for an easy access (and that incidentally is another reason why XMLConfig is something you should think twice about before making use of as sysadmins usually have their, let’s call it, well-grounded opinion about working with XML). Remember how several years ago some applications were doing crazy things like ..

<query id="get_customer">
  <table name="customer" pkey="cust_no">
    <columns>
      <column name="cust_name" />
      <column name="address" />
      <column name="phone_no" />
    </columns>
  </table>
  <operator name="EQ" />
</query>

.. instead of ..

get_customer = "SELECT cust_name, address, phone_no FROM customer WHERE cust_no=?"

.. and they used to call it being “XML-ready” or “XML-aware”? Well, if you catch yourself on doing similar things with IoC then you know you’ve gone too far :-)

If you happened to jump directly into running the code above instead of reading the text then you probably were wondering why the server had been started even though nowhere in the code we explicitly told it to. That’s because PyroServiceExporter is an InitializingObject – it’s a subclass of springpython.context.InitializingObject which means its after_properties_set method gets called right after all of its properties are resolved and set in place and it just happens that PyroServiceExporter starts a new server thread in its after_properties_set hook. If you scroll up to the beginning of this post you’ll recall that odd-looking service_exporter.after_properties_set() line that was advertized to ‘start the server’, which it did -  but if you’re using IoC, the container will call it on your behalf so that you don’t have to remember about it.

Other interesting classes which your objects may wish to subclass are springpython.context.ObjectPostProcessor and springpython.context.DisposableObject. Subclassing ObjectPostProcessor gives you two new methods to override – post_process_before_initialization which will be invoked before after_properties_set and post_process_after_initialization which will be called after after_properties_set will have been called. DisposableObject on the other hand lets you implement a method called destroy which will be called at the time when the container itself will be shutting down; to be precise, ApplicationContext registers its ‘shutdown_hook’ method to the Python stdlib’s atexit module and the shutdown hook is responsible for calling each of the disposable objects’ ‘destroy’ method; ‘destroy’ is the right place for your components to clean up after themselves, e.g. it can be used to release any external resources held during an object’s lifetime.

It’s worth noting that ApplicationContext may be passed in a list of configurations and although it won’t be used in examples, each of them may be of different type and that’s what I usually end up with, bits that I feel are more or less of a static nature are kept in YamlConfig and PythonConfig stores those which sometimes need to do something more before they’re ready to be used.

Before focusing on adding security features there’s still one thing that badly needs be improved, it’s the client code which knows nothing about IoC and breaks the DRY principle by duplicating configuration. In real world situation this could be in some degree expected, as both the server and a client could’ve been developed or operated by different teams or organizations but here it looks feebly, though at the same time it provides a good pretext for focusing a bit more on PythonConfig :-) Let’s rewrite it all into PythonConfig while keeping in mind the DRY rule then:

.
|-- client-main.py
|-- client_config.py
|-- common_config.py
|-- server-main.py
|-- server.py
`-- server_config.py
# client-main.py
 
# stdlib
import logging
 
# Spring Python
from springpython.context import ApplicationContext
 
# Our application
from client_config import ClientConfig
 
client_config = ClientConfig()
container = ApplicationContext(client_config)
 
# Fetch configuration from the container ..
log_level = container.get_object("log_level")
log_format = container.get_object("log_format")
 
# .. and configure logging.
logging.basicConfig(level=logging.getLevelName(log_level), format=log_format)
 
# .. fetch the service ..
service = container.get_object("service")
 
# .. invoke it ..
uptime = service.get_uptime()
 
# and print the output.
logging.info("Current uptime: [%s]" % uptime)
# client_config.py
 
# Spring Python
from springpython.config import Object
from springpython.remoting.pyro import PyroProxyFactory
 
# Our application
from common_config import CommonConfig
 
class ClientConfig(CommonConfig):
 
    @Object
    def service(self):
        service = PyroProxyFactory()
        service.service_url = "PYROLOC://%s:%s/%s" % (self.service_host(),
                                self.service_port(), self.service_name())
        return service
# common_config.py
 
# stdlib
import logging
 
# Spring Python
from springpython.config import Object
from springpython.config import PythonConfig
 
class CommonConfig(PythonConfig):
 
    @Object
    def service_host(self):
        return "127.0.0.1"
 
    @Object
    def service_port(self):
        return "16099"
 
    @Object
    def service_name(self):
        return "Service"
 
    @Object
    def log_level(self):
        return "DEBUG"
 
    @Object
    def log_format(self):
        return "%(asctime)s - %(levelname)s - %(process)d:%(threadName)s - %(name)s:%(lineno)d - %(message)s"
# server-main.py
 
# stdlib
import logging
 
# Spring Python
from springpython.context import ApplicationContext
 
# Our application
from server_config import ServerConfig
 
server_config = ServerConfig()
container = ApplicationContext(server_config)
 
# Fetch configuration from the container ..
log_level = container.get_object("log_level")
log_format = container.get_object("log_format")
 
# .. and configure logging.
logging.basicConfig(level=logging.getLevelName(log_level), format=log_format)
# server.py (no changes here)
 
# stdlib
import logging
import commands
 
class Service(object):
    def __init__(self):
        self.logger = logging.getLogger("%s:%s" % (__name__, self.__class__.__name__))
 
    def get_uptime(self):
        self.logger.info("get_uptime invoked")
        return commands.getoutput("uptime")
# server_config.py
 
# Spring Python
from springpython.config import Object
from springpython.remoting.pyro import PyroServiceExporter
 
# Our application
from server import Service
from common_config import CommonConfig
 
class ServerConfig(CommonConfig):
 
    @Object
    def service(self):
        return Service()
 
    @Object
    def exporter(self):
        exporter = PyroServiceExporter()
 
        exporter.service = self.service()
        exporter.service_name = self.service_name()
        exporter.service_host = self.service_host()
        exporter.service_port = self.service_port()
 
        return exporter

Methods decorated with an @Object decorator are turned into container-managed objects and by default they are stored in an internal cache of singleton objects as opposed to being fetched each time they are requested. Objects can also be lazily-initialized when they are first time needed by someone. Finally, they can be abstract and/or have parents. Let’s discuss the options through.

@Object is a short-hand form of @Object(scope.SINGLETON) and these two are equivalent.

# Spring Python
from springpython.config import Object
from springpython.config import PythonConfig
 
from foo import SomeClass
 
class MyConfig(PythonConfig):
 
    @Object
    def my_singleton(self):
        singleton = SomeClass()
        return singleton
# Spring Python
from springpython.context import scope
from springpython.config import Object, PythonConfig
 
from foo import SomeClass
 
class MyConfig(PythonConfig):
 
    @Object(scope.SINGLETON)
    def my_singleton(self):
        singleton = SomeClass()
        return singleton

The code below defines a regular object which won’t be stored in any cache, its value, and if fact the object returned, will be different each time the ‘random_password’ will be requested from a container.

# stdlib
from uuid import uuid4
 
# Spring Python
from springpython.context import scope
from springpython.config import Object, PythonConfig
 
class MyConfig(PythonConfig):
 
    @Object(scope.PROTOTYPE)
    def random_password(self):
        return uuid4().hex

If an object is marked as being lazily-initialized (which isn’t the default behaviour) it won’t be created until someone will try to reference it for the first time. This is in contrast to the default container’s action which is to eagerly create an object upon first seeing its definition in the config. In Python programming terms, it means that the first method below will be invoked as soon as the container will come across it whereas the second one won’t be.

# Spring Python
from springpython.config import Object
from springpython.config import PythonConfig
 
from foo import SomeClass
 
class MyConfig(PythonConfig):
 
    @Object
    def my_singleton(self):
        singleton = SomeClass()
        return singleton
# Spring Python
from springpython.config import Object
from springpython.config import PythonConfig
 
from foo import SomeClass
 
class MyConfig(PythonConfig):
 
    @Object(lazy_init=True)
    def my_singleton(self):
        singleton = SomeClass()
        return singleton

As in real life, parent-child relationships can be a bit more complex because an object can be both a parent and a child of yet another objects. Objects that shouldn’t be fetched directly from the container are quite obviously called abstract ones. If an object wishes to subclass another one, it needs to name the parent in its parent attribute. Note that credentials and crm_credentials objects below need to be made prototypes as they would be otherwise cached and crm_dev_credentials, crm_uat_credentials and ivr_credentials would be referencing the same Python objects.

# Spring Python
from springpython.context import scope
from springpython.config import Object
from springpython.config import PythonConfig
 
class Credentials(object):
    def __init__(self, app=None, user=None, password=None):
        self.app = app
        self.user = user
        self.password = password
 
    def __str__(self):
        return "%s %s %s" % (self.app, self.user, self.password)
 
class ServerConfig(PythonConfig):
 
    @Object(scope.PROTOTYPE, abstract=True)
    def credentials(self):
        return Credentials("MyApp")
 
    @Object(scope.PROTOTYPE, parent="credentials")
    def crm_credentials(self, credentials=None):
        credentials.user = "MYUSER"
        return credentials
 
    @Object(parent="crm_credentials")
    def crm_dev_credentials(self, credentials=None):
        credentials.password = "MYPASSWORD1"
        return credentials
 
    @Object(parent="crm_credentials")
    def crm_uat_credentials(self, credentials=None):
        credentials.password = "MYPASSWORD2"
        return credentials
 
    @Object(parent="credentials")
    def ivr_credentials(self, credentials=None):
        credentials.user = "FOO"
        credentials.password = "BAR"
        return credentials

Armed with all that knowledge we can finally start configuring security stuff. The method returning an uptime shouldn’t of course be troubled with authenticating incoming requests, that should be a responsibility of some kind of a security provider and the server should have a dependency on it. We’ll add a new module and update a few.

.
|-- client-main.py
|-- client.py
|-- client_config.py
|-- common_config.py
|-- security.py
|-- server-main.py
|-- server.py
`-- server_config.py

Only new or modified modules are shown below:

# security.py
 
class UsernamePasswordCredentials(object):
 
    def __init__(self, username, password):
        self.username = username
        self.password = password
 
    def __str__(self):
        return "&lt;%s at %s, username=%s&gt;" % (self.__class__.__name__, hex(id(self)),
                    self.username)
 
class UsernamePasswordSecurityProvider(object):
 
    def __init__(self, database=None):
        self.database = database
 
    def authenticate(self, credentials):
        if credentials.username in self.database:
            return self.database[credentials.username] == credentials.password
# server.py
 
# stdlib
import logging
import commands
 
class Forbidden(Exception):
    pass
 
class Service(object):
    def __init__(self, security_provider=None):
        self.security_provider = security_provider
        self.logger = logging.getLogger("%s:%s" % (__name__, self.__class__.__name__))
 
    def get_uptime(self, credentials):
        self.logger.info("get_uptime invoked")
 
        if self.security_provider.authenticate(credentials):
            self.logger.info("Letting the client in")
            return commands.getoutput("uptime")
 
        self.logger.info("Unknown client %s" % credentials)
 
        raise Forbidden("No chance mate!")
# server_config.py
 
# Spring Python
from springpython.config import Object
from springpython.remoting.pyro import PyroServiceExporter
 
# Our application
from server import Service
from common_config import CommonConfig
from security import UsernamePasswordSecurityProvider
 
class ServerConfig(CommonConfig):
 
    @Object
    def service(self):
        service = Service()
        service.security_provider = self.security_provider()
 
        return service
 
    @Object
    def exporter(self):
        exporter = PyroServiceExporter()
 
        exporter.service = self.service()
        exporter.service_name = self.service_name()
        exporter.service_host = self.service_host()
        exporter.service_port = self.service_port()
 
        return exporter
 
    @Object
    def security_provider(self):
        security_provider = UsernamePasswordSecurityProvider()
        security_provider.database = self.security_database()
 
        return security_provider
 
    @Object
    def security_database(self):
        return {"FOO": "BAR"}
# client-main.py
 
# stdlib
import logging
 
# Spring Python
from springpython.context import ApplicationContext
 
# Our application
from client_config import ClientConfig
from security import UsernamePasswordCredentials
 
client_config = ClientConfig()
container = ApplicationContext(client_config)
 
# Fetch configuration from the container ..
log_level = container.get_object("log_level")
log_format = container.get_object("log_format")
 
# .. and configure logging.
logging.basicConfig(level=logging.getLevelName(log_level), format=log_format)
 
# .. fetch the service ..
service = container.get_object("service")
 
# .. invoke it ..
credentials = UsernamePasswordCredentials("FOO", "BAR")
uptime = service.get_uptime(credentials)
 
# and print the output.
logging.info("Current uptime: [%s]" % uptime)

It’s the security provider’s burden to authenticate clients and server only needs a simple yes/no decision before returning data or raising an exception. Setting it up in that fashion, the server won’t have to be touched at all should we wish to change providers and start authenticating clients in some other way, for instance, through SSL certificates. And I know you’ll start yawning when I tell you once again that I think it’s not a provider’s business how to get its hand on the usernames/passwords database either, it just needs to operate on it.

A nice side-effect of not importing dependencies directly is that it’s easier to test the components in isolation without resorting to patching (which still comes handy at times) – replacing real objects with mocks and stubs becomes only a matter of a container’s returning different objects, though of course they still need to coded to given interfaces. Given that PythonConfig is pure Python code, it’s laughably easy to use  it in tests, you just need to subclass the real config and return mock objects instead of real ones. For instance, we don’t really need to start a new Pyro thread just to make sure server and security provider can play nicely together – Pyro is just the transport layer and has nothing to do with how other components co-operate.

.
|-- client-main.py
|-- client.py
|-- client_config.py
|-- common_config.py
|-- security.py
|-- server-main.py
|-- server.py
|-- server_config.py
|-- server_test_config.py
`-- test_all.py

(Only new code below)

# server_test_config.py
 
# Spring Python
from springpython.config import Object
 
# Our application
from server_config import ServerConfig
 
class _DummyExporter(object):
    pass
 
class TestServerConfig(ServerConfig):
 
    @Object
    def exporter(self):
        return _DummyExporter()
# test_all.py
 
# stdlib
import unittest
 
# Spring Python
from springpython.context import ApplicationContext
 
# Our application
from server_test_config import TestServerConfig
from security import UsernamePasswordCredentials
 
class ServerTestCase(unittest.TestCase):
 
    def setUp(self):
        self.container = ApplicationContext(TestServerConfig())
        self.default_credentials = UsernamePasswordCredentials("FOO", "BAR")
 
    def tearDown(self):
        self.container.shutdown_hook()
 
    def test_uptime(self):
        service = self.container.get_object("service")
        self.assertTrue(service.get_uptime(self.default_credentials))
 
if __name__ == "__main__":
    unittest.main()

Well, that’s about all for now. I’ve only touched the tip of the iceberg and showed you toy-size examples though it is almost always the case that IoC starts to shine when the code gets bigger and bigger -  it’s just that creating a full-fledged application seemed a bit too much for a blog post :-) Is IoC a panacea? Of course it isn’t, when not used judiciously you can quickly go from one extreme to another and instead of having dependencies intertwined right in the code you can lose the sight of the bigger picture of how control flows through an application’s building blocks simply because everything will seem too magical and declarative. As always, don’t overengineer things and don’t overdo with IoC, especially if you choose to use XML.

There’s also a question of whether Python really needs IoC, isn’t that really useful only in less dynamic languages like Java. Well, I truly believe that IoC should not really, or maybe not only, be thought of as a way to circumvent their way of dealing with changes to the source code, namely, that it needs to be recompiled each and every time, which is something that sometimes takes ages. It’s rather a fine way of bringing in more order and letting the programmers focus on their job while at the same time letting them be less afraid of introducing changes which could otherwise have a negative impact on applications. And it really helps in testing!

In case you ever need help with Spring Python or just want to chat, here’s the mailing list, a forum, a LinkedIn group,  an IRC #springpython channel on Freenode network and there’s also a Spring Python 1.1 book upcoming.

@fourthrealm

Share
Categories: Software Tags: ,