Armin Ronacher

Back from Ireland

written by Armin Ronacher, on Sunday, August 27, 2006 0:00.

When you are comming home to Austria from another country (I was in Ireland until yesterday) you always think of how beautiful your country is. This time too. almost.

Ireland is a really strange country. On the one side the history of Ireland is all about burning down religious places, fighting against the British, vikings and their own Irish people. But it really looks like the country is developing in a very different way today. Whilst the religious conflict still exists many people who left the country are comming back and even more are immigrating to Ireland. About hundred years ago most of the people in that country were farmers, some lived in cities but many lived out in the wilderness where nothing but turf existed.

Now the whole situation changes, but it looks like the people don't change in the same speed. When they were farmers they burned many calories and ate much heavy food like eggs, bacon, black pudding etc. Now they still eat that much ashore but they don't need that heavy food any more. The result is that many of those people are now overweight. Its crazy when you watch families buying food at a local spar. They put things into the cart which you wouldn't eat in those amounts...

But when you have a look at the number of young children you wonder why there are so many in Austria. A friend of our family told us that this is probably because the south is very Catholic and if you look at the statistics the amount of births is decreasing. The richer a country gets the lower the amount of your children. If I could believe him the hole situation will get worse in the next two generations.

The next thing you notice when you travel through Ireland is the high number of new houses which are all marked as "for sale". In Ireland there are some astate agents like Sherry Fitzgerald who build houses like mad and sell them for prices the average Irishman can't afford. Crazy world. Maybe they think the people immigrating would buy that.

Aside from that: Ireland is great. Navigating a boat on the Shennon is great fun and you can see really beautiful towns and cities. I really would like to have beautiful cities like those here too. But in our town they don't build beautiful houses, the build houses which look daring for two years, average for three and ugly for the rest. In Hermagor you can see ugly buildings like the house where the "Drogariemarkt" was, and now our local electrician is, the "Riedergarten" building where one of the two local spars is in and last but not least the new "Hofer" building and the awkward "Deichmann" and the other stupid capitalistic muck stores are in. Hermagor looks like the playground of architects and building enterprises who try to copy good looking modern buildings but fail on all aspects. But they are still able to sell their goddamn architecture as "modern".

And all just because our mayor and his cortege are easy to blend.

Goddamn.....

Anyway. Austria still rocks and Ireland was cool too ;-)

PS: pictures of ireland will follow in the next days. hopefully

Two Weeks Ireland

written by Armin Ronacher, on Friday, August 11, 2006 0:00.

Wohoo. I'm offline two weeks from today. Ireland, I'm comming

Ireland

Everybody who needs something from me: Haa haa ^^

RRRRRuby ;-)

written by Armin Ronacher, on Wednesday, August 9, 2006 0:00.

The last two days i had a deeper look at ruby and found together with __doc__ from #python.de some strange things. Before I discovered those things I really thought ruby was python with a little different syntax. But it seams like ruby is more perlish than pythonic. Read on my dear.

Disclaimer: if you are a ruby user you probably find the example from above ok, then just don't read that post. IMHO just python users may find this shocking ;-)

As a python programmer i know that whitespace is significant. But there are some positions in a language where whitespace shouldn't be significant like whitespace before and after operators. But have a look at the following example:

First we define a function

irb(main):001:0> def a
irb(main):002:1>  2
irb(main):003:1> end

And then we call it:

irb(main):004:0> a + 2
=> 4

This works because ruby doesn't require braces to call a function, but you can also call it by using this:

irb(main):005:0> a() + 2
=> 4

That's really okay for now. But this; isn't:

irb(main):008:0> a() +2
=> 4
irb(main):009:0> a +2
ArgumentError: wrong number of arguments (1 for 0)
        from (irb):9:in `a'
        from (irb):9:in `Kernel#binding'
        from :0

And that's just one of the problems with non first-class functions as you can see later. But methods in ruby lay in its own namespace. At least that's what the guys from #ruby-de told me. And this brings some problems again:

irb(main):001:0> def a() 2 end
=> nil
irb(main):002:0> a
=> 2
irb(main):003:0> a()
=> 2
irb(main):004:0> a = 1
=> 1
irb(main):005:0> a
=> 1
irb(main):006:0> a()
=> 2

whoops? What's that? That's one of the negative aspects of a) methods in its own namespace and b) non first-class methods.

This python snippet:

>>> def foo():
...  return 42
...
>>> bar = foo
>>> bar()
42
Looks like this in ruby:
irb(main):001:0> def foo()
irb(main):002:1>  42
irb(main):003:1> end
=> nil
irb(main):004:0> bar = method(:foo)
=> #
irb(main):005:0> bar.call
=> 42
irb(main):006:0> bar[]
=> 42

:foo is a interned symbol in ruby, something like a normal python string. Since ruby strings are mutable they arn't that cheep as python strings, so they have symbols. But writing :foo doesn't mean that you directly reference to foo. So method(:bar) looksup the method in the method namespace and creates a new instance of it. Or something like this. The result is that you can't just call the method by writing bar, but they have overloaded [] so that it calls the method...

But there is more in rubyland that smells odd. Take this python example:

class Foo(object):
    pass

def bar():
    return 4

f = Foo()
f.bar = bar
print f.bar() #prints 4

Looks like this in ruby:

class Foo
end

def bar
    4
end

f = Foo.new

q = class << f
    self
end
tmp = method(:bar)
q.class_eval {
    define_method(:bar, tmp)
}

puts f.bar #prints 4

And that's all just because there are no first-class functions ;)

And something I can't explain myself over which i stumbled while trying to build a closure with ruby:

irb(main):001:0> def foo
irb(main):002:1>  def bar
irb(main):003:2>   42
irb(main):004:2>  end
irb(main):005:1> end
=> nil
irb(main):006:0> foo
=> nil
irb(main):007:0> bar
=> 42

That's something i really can't explain myself...

Maybe someone can explain me those things, I really don't understand why ruby behaves like this. If there is an error in the examples above inform me about it.

Setuptools Plugins

written by Armin Ronacher, on Sunday, July 30, 2006 0:00.

Welcome to part #2 of the Python Plugin System Tutorial. In this part of the tutorial I'll explain how to use setuptools to create a plugin system.

It really looks like eggs are the most hyped python related thing next to WSGI at the moment. Many applications and Frameworks like TurboGears, Trac, Paste and Pylons use eggs for their plugins. This isn't surprising since eggs are very easy to distribute.

The core of setuptools are the two modules setuptools and pkg_resources. The former is required for the setup.py which is the core of each egg. The latter allows us to query those created eggs when they export entrypoints.

WTF are entrypoints?

The peak wiki explains entry points in this manner:

setuptools supports creating libraries that "plug in" to extensible applications and frameworks, by letting you register "entry points" in your project that can be imported by the application or framework.

For example, suppose that a blogging tool wants to support plugins that provide translation for various file types to the blog's output format. The framework might define an "entry point group" called blogtool.parsers, and then allow plugins to register entry points for the file extensions they support.

This would allow people to create distributions that contain one or more parsers for different file types, and then the blogging tool would be able to find the parsers at runtime by looking up an entry point for the file extension (or mime type, or however it wants to).

So if we look back to the first part of the tutorial we used a list of capabilities. Basically we could Now create an entrypoint of each of those capabilitities. But we won't do that. Why? Because of three reasons:

  • Each time you change one entrypoint you have to rebuild the egg-info folder.
  • When the developer adds an feature to the plugin he would have to edit the setup.py file too.
  • It's more complex to implement

You still want to use more than one entry point you can do so but this tutorial won't cover that case.

In this example the application is called myapplication.py and all plugins lay in an subfolder called plugins. We will call the entrypoint for the plugins myapplication.plugins.

So we should create a folder structure like that:

myapplication/
  myapplication.py      an empty file by now
  plugins/              an empty folder for all plugins

The first plugin

At first we have to create a new plugin, in this case we call it foo. Therefore we create a new folder structure below myapplication/plugins:

foo/
  foo/
    __init__.py         an empty file
  setup.py              an empty file

The next step will be adding content to the setup.py file:

# -*- coding: utf-8 -*-
"""
A small example plugin
"""
from setuptools import setup

__author__ = 'Your Name Here'

setup(
    name='Foo',
    version='1.0',
    description=__doc__,
    author=__author__,
    packages=['foo'],
    entry_points='''
    [myapplication.plugins]
    Foo = foo:FooPlugin
    '''
)

This file should be simple to understand, basically it's a normal distutils setup file. The difference is that we use distutils over setuptools and that he have defined an entrypoint. This entrypoint basically tells the application that the "Foo" plugin is a class called FooPlugin and located inside of the "foo" package.

Now we open the empty __init__.py file and add the following content:

# -*- coding: utf-8 -*-

class FooPlugin(object):
    capabilities = ['foo_capability']

    def do_something(self):
        return 'Hello from %s' % self.__class__.__name__

This file looks like the plugins from the first part of the tutorial but it doesn't have to inherit from a base class. Here we just use the generic object baseclass which is the parent of all new style classes.

Now we have a folder structure for an egg. but not an egg. Since we don't want to rebuild an egg each time we change something on the sourcecode we use the develop option of the setup.py file. Therefore we open a shell and go to the folder with the setup.py file and execute the following command:

$ python setup.py develop --install-dir .. -m

The -m option is required, otherwise setuptools will fail because it can't find the ".." folder in the PYTHONPATH.

The Main Application

Now we have an egg in development mode. Basically it's a file called Foo.egg-link with the path to the sources in it.

Time to create the application:

# -*- coding: utf-8 -*-
import os
import sys
import pkg_resources
sys.modules['myapplication'] = __import__(__name__)

ENTRYPOINT = 'myapplication.plugins'
PLUGIN_DIR = os.path.join(os.path.dirname(__file__), 'plugins')

def init_plugins():
    pkg_resources.working_set.add_entry(PLUGIN_DIR)
    pkg_env = pkg_resources.Environment([PLUGIN_DIR])
    plugins = {}
    for name in pkg_env:
        egg = pkg_env[name][0]
        egg.activate()
        modules = []
        for name in egg.get_entry_map(ENTRYPOINT):
            entry_point = egg.get_entry_info(ENTRYPOINT, name)
            cls = entry_point.load()
            if not hasattr(cls, 'capabilities'):
                cls.capabilities = []
            instance = cls()
            for c in cls.capabilities:
                plugins.setdefault(c, []).append(instance)
    return plugins

plugins = init_plugins()

That looks complex. But it isn't. The sys.modules thingy is not needed in real applications, but since this application is a one file application it won't appear in sys.modules and plugins would have problems importing it. So we put the current file into sys.modules.

The init_plugins function basically scans the plugins folder for eggs whose entry point is myapplication.plugins, load that egg and use the returned class to look up the capabilities. After that it instanciates the class and creates a dict in the following structure:

{'capability': [list, of, plugins]}

Basically this now allows you to select all plugins of a given capability by doing this:

for plugin in plugins.get('my_capability', []):

For the sake of simplicity we can create two methods for querying plugins:

def get_plugins_by_capability(capability):
    return plugins.get(capability, [])

def get_all_plugins():
    result = set()
    for p in plugins.itervalues():
        for plugin in p:
            result.add(plugin)
    return list(result)

Other plugins now could query plugins on their own by importing those methods from the myapplication module. For example here a Bar plugin:

# -*- coding: utf-8 -*-
import myapplication

class BarPlugin(object):
    capabilities = ['foo_capability']

    def do_something(self):
        plugins = myapplication.get_all_plugins()
        return 'Number of plugins: %d' % len(plugins)

The main application now can gain a main method:

def main():
    for plugin in get_plugins_by_capability('foo_capability'):
        print '%s: %s' % (plugin, plugin.do_something())

if __name__ == '__main__':
    main()

And the output would look like this:

$ python myapplication.py
<foo.FooPlugin object at 0xb7ca59ec>: Hello from FooPlugin
<bar.BarPlugin object at 0xb7ca5cec>: Number of plugins: 2

I personally don't use egg files beside for working on trac plugins so I'm not sure if my method of loading egg files is the best. If someone has a better way for loading egg files from a given plugin folder drop me a line :)

You can download an archive of all files here: setuptools_plugins.tar.gz

PHP Developer Quits

written by Armin Ronacher, on Sunday, July 30, 2006 0:00.

Some days ago sniper aka Jani Taskinen quit his work for the PHP project. At first I had to laugh because I thought be quit because PHP sucks ;-). But then I read the comments on slashdot...

mkavanagh2 posted on slashdot this irclog:

<_sniper_> hehehehe..
<_sniper_> all other members of the UN security council wanted to
           condemn Israel for attacking the UN post but USA (freedom and
           democracy) vetoed it....Israel says the resolution was fair.
<_sniper_> hell yeah..
<_sniper_> NUKE ISRAEL!
<_sniper_> I'm so full of that fucking country..
<Shai-Tan> indeed
<_sniper_> Eye for an eye..I'll kill one Israel officer for one of ours,
           is that fair?
<_sniper_> I bet I'll be hanged for that.
<_sniper_> They kill one of my brother-in-arms-for-peace..I think I'm 
           entitled to kill one of their nazis.
<_sniper_> Hezbollah, where can I enlist?
<_sniper_> FYI: I don't care at all what anybody thinks about me. I'm 
           going to be openly anti-Israel from now on. This was the last
           straw for me. Fuck you jews.
<_sniper_> I will also quit this project. As long as it's backed by some
           Israel company, I don't want to have anything to do with it.
<_sniper_> Good bye.
<-- _sniper_ (~jani@a88-112-115-63.elisa-laajakaista.fi) has left #php.pecl

And from another comment i know that:

[...] Jani himself has served as a UN peace keeper in Southern Lebanon and has been at the receiving end of both Israel and Hezbollah fire. This may entitle him to have strong personal feelings about the recent death of a Finnish peace keeper at the same location, along ones from other countries.

Why can't humans stop wars? I really hate that. Now there is another person in that world that can't stand Jews just because of a stupid war.