Monthly Archives: August 2013

NiteoWeb attended a Pyramid sprint in Halle, Germany

Gocept, a company based in Halle (Saale), Germany, organized a Pyramid sprint, which lasted from 15th to 17th August 2013. The sprint took place at their headquarters which, by the way, has a lovely garden perfectly suited for relaxation, eating, drinking and development (not necessarily in that order!).

A bunch of NiteoWeb former and present employees took part, too. Despite the fact that Halle is about 10 hours away from Ljubljana if you go by car (quite a long ride indeed!), but it was well worth coming there. Gocept did an excellent job of feeding and entertaining all the sprint participiants and it was a great pleasure to meet Chris McDonough, author of the Pyramid web framework, in person. An interesting and amusing dude I must say.

Happy sprint participants were quite productive and a whole bunch of bug fixes and enhancements have been made – see the wrap up for more details. The only real downside was that the sprint ended so early, three days really passed in the blink of an eye. But hey, isn’t that always the case when you’re having fun?

So Gocept, thanks again for everything and hope to see you in 2014!

Setuptools – run custom code in setup.py

A week or so ago I started developing an experimental Python package for one of our projects. At some point I realized that it would be convenient to automatically execute some additional initialization code during the package installation process (i.e. when “python setup.py install” is run).

This can be achived by subclassing the setuptools.command.install class and overriding its run() method, like this (in setup.py):

from setuptools import setup
from setuptools.command.install import install


class CustomInstallCommand(install):
    """Customized setuptools install command - prints a friendly greeting."""
    def run(self):
        print "Hello, developer, how are you? :)"
        install.run(self)


setup(
    ...

NOTE: We reference the parent class’ run method directly – we can’t use super(…).run(self), because setuptools commands are old-style Python classes and super() does not support them.

Now that we have a customized install class, we must tell the setuptools machinery to actually use it instead of the built-in version. We do this through the cmdclass parameter of the setup() function:

...

setup(
    ...

    cmdclass={
        'install': CustomInstallCommand,
    },

    ...
)

The value of the cmdclass parameter should be a dictionary whose keys are the names of the setuptools commands we’re customizing (‘install’ in our case), while the corresponding values are our custom command classes we have defined eariler (CustomInstallCommand in this example).

BONUS

Sometimes you will want to apply the the same modification to more than a single command class. For instance your package could also be installed in development mode (by running python setup.py develop), meaning that the setuptools.command.develop class should be overriden as well in order for your modifications of the installation procedure to have any effect in this scenario, too.

A straightforward approach would be to implement another class (e.g. CustomDevelopCommand) similar to the the existing CustomInstallCommand class, but this would violate the DRY principle (“don’t repeat yourself”). What you can do is to define a decorator which accepts command class as a parameter, modifies its run() method and returns a modified version of the class.

Here’s an example:

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install


def friendly(command_subclass):
    """A decorator for classes subclassing one of the setuptools commands.

    It modifies the run() method so that it prints a friendly greeting.
    """
    orig_run = command_subclass.run

    def modified_run(self):
        print "Hello, developer, how are you? :)"
        orig_run(self)

    command_subclass.run = modified_run
    return command_subclass

...

@friendly
class CustomDevelopCommand(develop):
    pass

@friendly
class CustomInstallCommand(install):
    pass


setup(
    ...

It’s very simple – we just replace the run() method of a command class with our customized version of it and then apply the decorator where necessary. If we later need to replace the greeting with something different, we only have to change the code in one place.

NOTE: Do not forget to provide the right value of the cmdclass parameter to the setup() function.

By the way – you might be looking at the decorator code and wondering why we explicitly store a reference (‘orig_run’) to the original run method. The reason is we can’t simply call command_subclass.run() in modified_run function directly, because that would cause an infinite loop!
Just look at the code carefully – at the end of the decorator, command_subclass.run becomes a reference to modified_run. If modified_run then calls command_subclass.run(self) in its body, it actually calls itself – again and again and again, until maximum recursion depth is exceeded. Explicitly storing a reference to the original run() method is thus not redunant at all, it’s simply necessary.