Author Archives: Peter Lamut

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.

Write a Plone CLI maintenance script

This is a quick tip on how to write your own command line maintenance scripts for your Plone application.

Recently one of our clients expressed a need for a maintenance script which would walk the database of a Plone application and, for every object, print out all the roles users have assigned on that object. Since we were dealing with a large database, processing it would take a considerable amount of time, rendering a solution with a browser view (or similar) not particularly useful. We needed some kind of a command line utility which would occasionally be run in the background (e.g. as a cron job) and would output results to a file.

The question which arised next was how to write such a Python script so that it would hook up to the Plone application, its database and would at the same time already have access to all the Plone utilities it might need (i.e. Products.CMFCore). I searched around the internet quite a bit before I finally stumbled upon the missing part.

It turned out to be pretty easy actually. The key is to define a zopectl.command entry point in your package’s setup.py (i.e. in a package containing your maintenance script):

setup(
    ...

    entry_points="""
    [zopectl.command]
    dump_roles = your.package.module:some_callable
    """,

    ...
)

You can then add this package as a dependency of the bigger Plone project, run the buildout and there it is – your maintenance script (named dump_roles in our example) can be called like this:

$ bin/instance dump_roles <arguments>

When you run the command, some_callable from the your.package.module (as defined in setup.py) will be invoked. The callable will receive two arguments – the Zope root application object (as a starting point of object traversal) and the additional command-line arguments that might have been used on script invocation.

For the sake of completeness, here’s a skeleton of the actual maintenance script (defined in your.package.module):

def some_callable(app, cmd_args):
    """Module's entry point (zopectl.command).

    :param app: Zope root application object
    :param cmd_args: list of command line arguments used to invoke the command
    """
    pass  # your maintenance code goes here ...

Happy coding!

Convert z3c.form field desc. to tooltip

Let’s say you have a typical form with some input fields. By default z3c.form displays a description (if provided in form definition) above each form field, like in the screenshot below for example:

Original form

Sometimes however, you might want to make things a little bit different. Perhaps you want to save some screen space by hiding field descriptions, but still want to provide helpful additional information on form fields to your users. One way of achieving this is to display field descriptions as tooltip text:

Modified form with tooltips

Not bad.

And it’s easy too. Simply set the title attribute of a corresponding form field and you’re done.

I’ll show you how we did it for one of our clients. The form was called List Events, because, well, it lists upcoming events based on search criteria.

# file eventlist.py in browser directory
...
from z3c.form import form
...

class ListEventsForm(form.Form):
    ...

    def updateWidgets(self):
        """Move fields' descriptions to title attributes of HTML form elements."""
        super(ListEventsForm, self).updateWidgets()
        for name, widget in self.widgets.items():
            widget.title = widget.field.description

In the ListEventsForm class we override the updateWidgets method in order to iterate through all form fields and set their title attribute.

Note that this makes tooltips to show, but field descriptions themselves are still visible. We hide them with the following CSS rule (“eventlist-form“ being our form’s ID):

#eventlist-form div.formHelp {
    display: none;
}

And that’s all, folks!

How to change element’s ID with Diazo?

A common scenario: on your website all subpages share a common header, but you want a different header on the front page. Let’s say you differentiate between both header versions by their ID attribute and define two different sets of CSS rules for each version.

When applying Diazo rules to a theme file, you therefore need to change header element’s ID, depending on whether the first page or one of the subpages was requested. Here’s a snippet from rules.xml, which does exactly that:

<!-- change header's ID attribute -->
<prepend css:theme="#header-index">
    <xsl:attribute name="id">header-subpage</xsl:attribute>
</prepend>

ID of the header as defined in theme file (header-index) is changed to header-subpage after the rule above is applied.

The rule basically says “Match #header-index element in theme file and use some inline XSL on it”. The “xsl:attribute” tag matches current element’s attribute whose name is “id” (with “current element” being the #header-index element as matched by the outer <prepend> tag). The content of the “xsl:attribute” tag is a new value for the ID attribute.

Nothing spectacular here indeed, but I lost quite some time trying to figure out how to do it in a simple yet efffective way. Very frustrating for such a small task. Various suggestions found on Google simply didn’t work or were a bit too complicated (there must be an easier way to do it, right?).

So to help you avoid all the trouble, I decided to wrote this blog post. Too bad it didn’t exist before. 😉