Spring Python 1.1 book review

August 22nd, 2010 Dariusz Suchojad No comments

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.

  • Share/Bookmark
Categories: Software Tags: ,

ToStringBuilder.reflectionToString in Python

August 20th, 2010 Dariusz Suchojad No comments

I use Apache Commons ToStringBuilder.reflectionToString whenever I code in Java and thought it would come handy to have a similar construct in Python. What I’ve finally come up with is called make_repr and may be downloaded here along with a simple usage example (it’s all Python license).

So how does it work? Say you have a class like the one below

class Foo(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

and want to add a nice string representation of it. You could carefully pick the attributes manually and add them to the __repr__ method or you can use make_repr to achieve what follows (I’m assuming make_repr has been saved to a util.py module):

from util import make_repr
 
class Foo(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
 
    def __repr__(self):
        return make_repr(self)
 
print Foo(1,2,3)

Which will show <Foo at 0×7f2ed9873510 x=[1] y=[2] z=[3]> in the terminal. Callable objects won’t be returned and by the default attributes shown will be sorted alphabetically while any attributes with names starting with a double underscore will be ignored. Another customization option is to_avoid_list – if there’s a class attribute which goes by the name it points to (by default it’s repr_to_avoid, it must be in iterable object, such as a tuple or a list whose elements are names of attributes that must not be returned on the output, like below:

from util import make_repr
 
class Foo(object):
 
    repr_to_avoid = ("x",)
 
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
 
    def __repr__(self):
        return make_repr(self)
 
print Foo(1,2,3)

Noticed that “x” wasn’t returned on the output?

Well, that’s about it, I hope you like the little tool :-)

  • Share/Bookmark
Categories: Software Tags: ,

WebSphere MQ and Ubuntu HOWTO

July 3rd, 2010 Dariusz Suchojad No comments

Until IBM finally recognizes that Ubuntu is the most popular Linux distribution and starts offering WebSphere MQ DEBs to install, here’s a small HOWTO which will guide you through the installation process. I’m using Ubuntu 9.10 and MQ 7.0.1 (CZ4VEML), both 64-bits, but it’s something I’ve been using since at least Ubuntu 7.04  I think, so it will work reliably with other versions of Ubuntu and MQ as well.

Installation



First untar the CZ4VEML.tar.gz archive and then install rpm and sharutils packages:

dsuch$ sudo apt-get install rpm sharutils

Next try to execute the ./mqlicense.sh script which will most probably fail horribly but that’s OK, we’ll work around it

dsuch$ sudo ./mqlicense.sh

Accept the license if it doesn’t end with an error such as the one below ..

Exception in thread "main" java.lang.UnsatisfiedLinkError: fontmanager
(libstdc++.so.5: cannot open shared object file: No such file or directory)

.. but if it does, just read the license carefully

dsuch$ less ./licenses/LA_en

I’m assuming the script has failed but if you take a look at it closely you’ll notice that all it does in the end is to create a /tmp/mq_license/license/status.dat file, so we’ll do the same ourselves a couple of times.

Now comes the runtime, preceded by the manual creation of the file which ./mqlicense.sh failed to create.

dsuch$ sudo mkdir -p /tmp/mq_license/license/
dsuch$ sudo touch /tmp/mq_license/license/status.dat
dsuch$ sudo rpm -iavh --nodeps --force-debian
./MQSeriesRuntime-7.0.1-0.x86_64.rpm

.. more RPMs to install ..

dsuch$ sudo mkdir -p /tmp/mq_license/license/
dsuch$ sudo touch /tmp/mq_license/license/status.dat
dsuch$ sudo rpm -iavh --nodeps --force-debian ./MQSeriesJava-7.0.1-0.x86_64.rpm
./MQSeriesClient-7.0.1-0.x86_64.rpm ./MQSeriesServer-7.0.1-0.x86_64.rpm
./MQSeriesSDK-7.0.1-0.x86_64.rpm ./MQSeriesSamples-7.0.1-0.x86_64.rpm
./MQSeriesTXClient-7.0.1-0.x86_64.rpm
 

.. and the last batch of RPMs ..

dsuch$ sudo mkdir -p /tmp/mq_license/license/
dsuch$ sudo touch /tmp/mq_license/license/status.dat
dsuch$ sudo rpm -iavh --nodeps --force-debian  ./MQSeriesMan-7.0.1-0.x86_64.rpm
./MQSeriesKeyMan-7.0.1-0.x86_64.rpm 

The newly created mqm user would sure like to use Bash by default ;-)

dsuch$ sudo usermod -s /bin/bash mqm

That’s all there is to installing, let’s try to send some messages.

Verifying the installation



First change the user to mqm ..

dsuch$ sudo su - mqm

.. and create & start a QM01 queue manager:

mqm$ crtmqm QM01
mqm$ strmqm QM01

Let’s define a Q1 local queue for testing

mqm$ runmqsc QM01

Now cd to /opt/mqm/samp/bin/ which holds various precompiled utilities among which are amqsput and amqsget. By the way, the source code is in /opt/mqm/samp.

Send two messages to the Q1 queue on the QM01 queue manager and quit amsqput with Ctrl-C:

mqm$ ./amqsput Q1 QM01
Sample AMQSPUT0 start
target queue is Q1
123
zxc
^C

Now let’s use amqsget to get the messages off Q1 queue and quit with Ctrl-C again, as you can see, there are 2 messages sent there in the previous step:

mqm$ ./amqsget Q1 QM01
Sample AMQSGET0 start
message <123>
message <zxc>
^C


Removing WebSphere MQ



Use those three commands if for some reason you need to remove MQ from your system.

dsuch$ sudo rpm -qa | grep "MQSeries" | xargs sudo rpm -e --force-debian --noscripts
dsuch$ sudo rm -rf /var/mqm
dsuch$ sudo userdel mqm

That’s all folks, the rest is in the MQ documentation, using MQ on Ubuntu is in no way different to what RHEL has to offer, it’s simply Linux and everything works just fine. Except the installer :-)

  • Share/Bookmark
Categories: Software Tags: ,

LNK1112 and plain setup.py

June 26th, 2010 Dariusz Suchojad No comments

I was scratching my head over why I couldn’t create a Windows AMD64 installer for PyMQI and even though I had Visual Studio 2008 Proffesional Edition installed I was still greeted with “LNK1112: module machine type ‘x64′ conflicts with target machine type ‘X86′”. All of the blog posts were mentioning various tweaks to nmake but that wasn’t actually helpful because I just wanted plain “python setup.py build” to work first and besides, I’m not using any makefiles.

Once again, turned out that reading the fine documentation should’ve been my first step. As you can read over there, for some unknown reason the compiler for 64-bit systems isn’t installed by default. Once I installed it, I found I could run a new “vcvarsx86_amd64.bat” command and then miraculously I could do “python setup.py build –plat-name=win-amd64 bdist_wininst” to make the installer :-)

  • Share/Bookmark
Categories: Software Tags:

Make mc remember the last directory

June 16th, 2010 Dariusz Suchojad No comments

This is mostly so I don’t forget about it myself.. when installing Ubuntu, don’t forget to add this line to ~/.bashrc and have Midnight Commander remember the last directory you were in on exit instead of taking you back to the one you were in when you typed mc in the shell:

source /usr/share/mc/bin/mc.sh
  • Share/Bookmark
Categories: Software Tags:

Intro To Spring Python Slides

June 3rd, 2010 Dariusz Suchojad 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.

  • Share/Bookmark
Categories: Software Tags:

How to read PKG-INFO metadata off a Python .egg distribution

It’s obvious when you see it but somehow I’ve just spent an hour on figuring out how to read a PKG-INFO metadata file off a Python .egg distribution, so here it is in case someone needs it some day :-)

# stdlib
import zipimport
 
# Distribute
import pkg_resources
 
egg_file = "/path/to/a/distribution-1.0-py2.6.egg"
dist = pkg_resources.Distribution.from_filename(egg_file,
             metadata=pkg_resources.EggMetadata(zipimport.zipimporter(egg_file)))
 
# pkg_info will now be equal to the contents of a PKG-INFO metadata file
pkg_info = dist.get_metadata("PKG-INFO")
  • Share/Bookmark
Categories: Software Tags:

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

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.

  • Share/Bookmark
Categories: Software Tags: ,

Spring Python, Pyro and remote services

April 25th, 2010 Dariusz Suchojad No comments

One of the Spring Python’s features is a wrapper around Pyro, a Python Remote
Objects library which makes it very easy to expose Python applications as network services
running across distributed systems. You write ordinary Python code that is unaware
of any networking and Spring Python lets you publish and invoke it through
its PyroServiceExporter and PyroProxyFactory objects. The setup uses a binary
pickle protocol underneath so it’s only available if both sides, both client and the
server, are written in Python.

Here’s how the service’s code for returning current system’s uptime might look
like. As you can see, there’s nothing Spring Python going on there and in fact
it’s just a simple class with just one method which knows nothing about Spring
Python nor is it aware that it’s going to be available through any network.
Staying out of your way and letting you reuse an already existing code is one
of the biggest advantages of Spring Python, sure, you need to learn its API
and principles but you can still simply code in Python and not be afraid of
getting caught in some artificial maze of interfaces and dependencies.

# stdlib
import logging
import commands

# 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()

# .. get the uptime ..
uptime = service.get_uptime()

# and print it on the console.
logging.info("Current uptime: [%s]" % uptime)

And here’s the Spring Python’s approach to exposing the service through Pyro
protocol, new bits have been highlighted in green. PyroServiceExporter is an
object which grabs a service, lets you set its name and let it run on a given
host and port. Note that the service’s code hasn’t been changed at all.

# 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()

Such a service needs a client now and here’s the code that invokes the server
looks like, key parts are in green again. PyroProxyFactory needs a server’s
location and then invoking a server is only a matter of invoking a method of
an object, it can’t be easier than that :-)

# 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)

Of course there’s still room for improvement. Firstly, there’s no authorization
of whatsoever, everyone can invoke the service. Secondly, the configuration of
both parties is written directly in the source code. It would be much better if
it all were externalized to some other place and that’s exactly what the next
installment will be about, we’ll be using Spring Python’s Inversion of Control
features to decouple the actual implementation from its configuration.

Update: here is the second part which shows Spring Python’s IoC in action.

  • Share/Bookmark
Categories: Software Tags: ,

Pika – Python + AMQP

February 24th, 2010 Dariusz Suchojad No comments

Przeprowadziłem ostatnimi dniami szczegółowe porównanie bibliotek AMQP dla Pythona i Pika jest tym, czego spokojnie będę używał. Badałem ją na różne sposoby, w testach wielowątkowych, wieloprocesowych, pod kątem wydajności oraz wygody użycia i to jest właśnie to :-)

  • Share/Bookmark
Categories: Software Tags: ,