Archive for the ‘Ordenadores’ Category

Pycha padding present and future

Sunday, September 13th, 2009

Simon Ilyushchenko sent me a patch some weeks ago about tick labels in Pycha. The patch fixes the label position in the case where it goes out of the surface dimensions. The problem with his patch is that is too specific and only works well for the most simple case. For example, it doesn’t solve the problem:

  • when you have rotated labels
  • when you have pie charts
  • for the y axis tick labels

And that’s why I didn’t add his patch to pycha. When developing the library I always try to make it as orthogonal and predictable as possible, so if a feature is added and it should work in all places where it makes sense. Users that send me patches are not usually concerned about edge cases but that’s my work as the library author and maintainer.

But the real point is that Simon raised a real issue with Pycha that I was worried about since the very beginning: right now the user has to adjust the padding options to make sure that tick labels and other things are kept inside the surface. Clearly this is suboptimal and for automatically computed charts without human intervention it can be a real issue.

So let me explain how pycha uses its real state space right now. First, the user tells the library how big the rendering surface is going to be: let’s call these parameters surface_width and surface_height. Then there are these padding options: padding.top, padding.bottom, padding.left and padding.right. Let’s see it in the following figure:

figure1

Now we have a padding area and a chart area. The chart area is where pycha draws the chart. The axis (when used) are drawn in the boundary of the chart area and the tick labels and axis titles are drawn in the padding rectangle. Other things like the chart title and the legend are also drawn in that rectangle. You can see it in the next figure where the chart area has a blue background:

figure2

Now, I want to change this and make Pycha automatically compute all its elements so the padding is actually that, blank space. Optimally Pycha should not draw anything into the padding rectangle. Well, there maybe some exceptions, see the end of this post for more information about them. So let’s define some new areas:

figure3

The goal is to make Pycha compute all these areas automatically so the chart area is reduced to accomodate all the other things the library draws in the surface without cluttering the padding area. This is a big change and it won’t happen for 0.5.2 but I’ll try to have it for the 0.6.0 release. Obviously this is a backwards incompatible change and new charts rendered with the same options will look smaller. Maybe I’ll set the default values for the padding options to zero to minimize the update impact.

The way Pycha will compute these areas is actually pretty similar than the way graphical toolkits like Gtk+, Tk, Qt, Swing, GWT do it when using layout containers where the widgets are placed in. There is a layout phase where the area’s dimensions are negociated and calculated and then there is a rendering phase when the elements/widgets are actually drawn. For bar and line charts this may look overkill but for other charts like pie charts is really the only sane way to do it.

The legend is a special case and I’m still not sure about positioning it using ‘absolute’ coordinates or give it its own area that is taken into account for the layout algorithm.

There are more than one way to do it

Sunday, April 19th, 2009

I wrote a method the other day. It was not a particularly difficult method and before writing it, it didn’t seem like a challenge. When I finished it, it looked quite good and simple but there was something that keep my eyes focused on a point instead of enjoying the method as a whole. Something similar as when you buy a shiny beatiful monitor, you plug it in and you discover it has a dead pixel. No matter how bright and fast your monitor is, that rotten pixel is ruining your experience.

Let me show you my broken pixel.

But before I’ll give you a small explanation of what the method does. Its class has a list of collectors, where each collector is a callable that return a generator of photos . The method collect the photos of all collectors until a maximum is reached, then it return the photos using an auxiliar method that does its own job postprocesing the list of photos.

Example carrusel

Example carrusel

Here is my initial version:


    def collect_photos1(self, destination):
        n_photos_collected = 0
        for collector in self.collectors:
            for photo_info in collector(destination):
                self.add_photo(photo_info)
                n_photos_collected += 1
                if n_photos_collected > self.max:
                    return self.get_photos()

        return self.get_photos()

As you can see, no rocket science so far. It’s just a nested for loop that iterates over all the photos until we get as many as we want. The rotten pixel is the return self.get_photos() line. It is bad because it’s duplicated, one in the finished condition and one at the end of the method. There are two problems with that duplication:

  • The first one is a practical problem. What if, in the future, the get_photos aux method need to receive a parameter. We need to update the call to that method, but as we have two calls there is a chance that we forget to update one of them. If we had only one the error probability of an update would be lower.
  • The second problem is a theorical one. We are using a nested for loop to iterate over a list of lists of photos but we do not know in advance how long those lists are and how many loop body we are going to iterate.

My second version is basically the same as the first but instead of duplicating the return self.get_photos line we are duplicating the break condition. Now, if we add a parameter to the get_photos method we will have to update just one call. But if we want to add another condition to stop collecting photos we will have to update two if statements. In other words, this version is pretty much the same.


    def collect_photos2(self, destination):
        n_photos_collected = 0
        for collector in self.collectors:
            for photo_info in collector(destination):
                self.add_photo(photo_info)
                n_photos_collected += 1
                if n_photos_collected > self.max:
                    break
            if n_photos_collected > self.max:
                break

        return self.get_photos()

Then I tried to convert the for loops into while loops since basic computer science tell us that a while loop is the choice to make when the number of iterations is unknown. So this version does not have the previous two problems and it’s easier to maintain. Nevertheless, it introduces another problem: it’s harder to read and to understand.


    def collect_photos3(self, destination):
        n_photos_collected = 0
        need_more_photos = True
        collectors_iterator = iter(self.collectors)
        while need_more_photos and collectors_iterator.has_next():
            collector = collectors_iterator.next()

            photos_iterator = collector(destination)
            while need_more_photos and photos_iterator.has_next():
                photo_info = photos_iterator.next()
                self.add_photo(photo_info)
                n_photos_collected += 1

                if n_photos_collected > self.max:
                    need_more_photos = False

        return self.get_photos()

Version 4 is a crazy one. It tries to simulate to goto statement in Python. Everybody will tell you the goto statement is evil and well, most of the times, it is. But sometimes it has no good replacement like this one where we want to stop two nested loops with a statement. Too bad Python does not have a goto statement :(


    def collect_photos4(self, destination):
        n_photos_collected = 0
        try:
            for collector in self.collectors:
                for photo_info in collector(destination):
                    self.add_photo(photo_info)
                    n_photos_collected += 1
                    if n_photos_collected > self.max:
                        raise TypeError('goto')

        except TypeError:
            pass

        return self.get_photos()

Now, what if we separate the two problems this method is trying to solve: iterating over the photos and adding to our result set. Doing so we can write a simple generator that gives us a photo at a time and then a while loop that check there are more photos in this generator and we actually want them. I like this version more than any of the previous one but still, the while loop is not very readable.


    def collect_photos5(self, destination):
        def photos_fetcher():
            for collector in self.collectors:
                for photo in collector(destination):
                    yield photo

        n_photos_collected = 0
        photos_iterator = photos_fetcher()
        while n_photos_collected < self.max and photos_iterator.has_next():
            photo_info = photos_iterator.next()
            self.add_photo(photo_info)
            n_photos_collected += 1

        return self.get_photos()

And then, the last version. I decided to add the stop condition logic into the generator and as it is a nested function I can put a return statement to exit from the two nested loops. Then the main loop can be a for loop without the boilerplate management code that the while loop needed.


    def collect_photos6(self, destination):
        def photos_fetcher(max_photos):
            n_photos_collected = 0
            for collector in self.collectors:
                for photo in collector(destination):
                    if n_photos_collected > max_photos:
                        return
                    yield photo
                    n_photos_collected += 1

        for photo_info in photos_fetcher(self.max):
            self.add_photo(photo_info)

        return self.get_photos()

What version do you like most?

Mapping inheritance to a RDBMS with storm. Autoproxy version

Tuesday, January 27th, 2009

We saw in the Proxy version that some types of queries were not possible using the lazr.delegates package. We solved that problem using Storm’s Proxy objects but we lost easyness in the process.

This time we will try to combine both aproaches to get the best of both worlds.

The interface definitions do not change:

    >>> from zope.interface import Interface, Attribute
    >>> class IPerson(Interface):
    ...     name = Attribute("Name")
    ...
    >>> class ISecretAgent(IPerson):
    ...     passcode = Attribute("Passcode")
    ...
    >>> class ITeacher(IPerson):
    ...     school = Attribute("School")

Neither the Person class:

    >>> from zope.interface import implements
    >>> from zope.interface.verify import verifyClass
    >>> from lazr.delegates import delegates
    >>> from storm.locals import Store, Storm, Unicode, Int, Proxy, Reference
    >>> class Person(Storm):
    ...     implements(IPerson)
    ...
    ...     __storm_table__ = "person"
    ...
    ...     id = Int(allow_none=False, primary=True)
    ...     name = Unicode()
    ...     person_type = Int(allow_none=False)
    ...     _person = None
    ...
    ...     def __init__(self, store, name, person_class, **kwargs):
    ...         self.name = name
    ...         self.person_type = person_class.person_type
    ...         store.add(self)
    ...         self._person = person_class(self, **kwargs)
    ...
    ...     @property
    ...     def person(self):
    ...         if self._person is None:
    ...             assert self.id is not None
    ...             person_class = BasePerson.get_class(self.person_type)
    ...             self._person = Store.of(self).get(person_class, self.id)
    ...         return self._person
    ...
    >>> verifyClass(IPerson, Person)
    True

Now, the real magic is in the metaclass. We use it not only to register our subclasses (so the Person.person property can find them) but to automatically store the attributes we needed to set manually in our previous version: the person_id and person attributes and a proxy object for each Person attribute. It’s like we are reimplementing inheritance in Python but not really :-)

    >>> from storm.properties import PropertyPublisherMeta
    >>> class PersonType(PropertyPublisherMeta):
    ...     def __init__(self, name, bases, dict):
    ...         if hasattr(self, '__storm_table__'):
    ...             # this need to be done before calling the superclass
    ...             # otherwise Storm will cry about not having a primary key
    ...             self.person_id = Int(allow_none=False, primary=True)
    ...
    ...         super(PersonType, self).__init__(name, bases, dict)
    ...
    ...         if not hasattr(self, '_person_types_registry'):
    ...             self._person_types_registry = {}
    ...         elif hasattr(self, '__storm_table__'):
    ...             key = len(self._person_types_registry)
    ...             self._person_types_registry[key] = self
    ...             self.person_type = key
    ...
    ...             self.person = Reference(self.person_id, Person.id)
    ...             self._add_proxy_properties()
    ...
    ...     def _add_proxy_properties(self):
    ...         for name in IPerson:
    ...             if not hasattr(self, name):
    ...                 remote_attr = getattr(Person, name)
    ...                 setattr(self, name, Proxy(self.person, remote_attr))
    ...
    ...     def get_class(self, person_type):
    ...         return self._person_types_registry[person_type]

Not our BasePerson is really simple

    >>> class BasePerson(Storm):
    ...     __metaclass__ = PersonType
    ...
    ...     def __init__(self, person):
    ...         self.person = person

And so are the subclasses. No repetition, so it is less prone to mistakes :-)

    >>> class SecretAgent(BasePerson):
    ...     implements(ISecretAgent)
    ...
    ...     __storm_table__ = "secret_agent"
    ...     passcode = Unicode()
    ...
    ...     def __init__(self, person, passcode=None):
    ...         super(SecretAgent, self).__init__(person)
    ...         self.passcode = passcode
    ...
    >>> verifyClass(ISecretAgent, SecretAgent)
    True
    >>> class Teacher(BasePerson):
    ...     implements(ITeacher)
    ...
    ...     __storm_table__ = "teacher"
    ...     school = Unicode()
    ...
    ...     def __init__(self, person, school=None):
    ...         super(Teacher, self).__init__(person)
    ...         self.school = school
    ...
    >>> verifyClass(ITeacher, Teacher)
    True

Let’s make sure our queries work as expected:

    >>> from storm.locals import create_database
    >>> database = create_database("sqlite:")
    >>> store = Store(database)
    >>> result = store.execute("""
    ...     CREATE TABLE person (
    ...         id INTEGER PRIMARY KEY,
    ...         person_type INTEGER NOT NULL,
    ...         name TEXT NOT NULL)
    ... """)
    >>> result = store.execute("""
    ...     CREATE TABLE secret_agent (
    ...         person_id INTEGER PRIMARY KEY,
    ...         passcode TEXT)
    ... """)
    >>> result = store.execute("""
    ...     CREATE TABLE teacher (
    ...         person_id INTEGER PRIMARY KEY,
    ...         school TEXT)
    ... """)
    ...
    >>> secret_agent = Person(store, u"James Bond",
    ...                        SecretAgent, passcode=u"007")
    >>> ISecretAgent.providedBy(secret_agent.person)
    True
    >>> teacher = Person(store, u"Albus Dumbledore",
    ...                  Teacher, school=u"Hogwarts")
    >>> ITeacher.providedBy(teacher.person)
    True
    >>> store.commit()
    >>> del secret_agent
    >>> del teacher
    >>> store.rollback()
    >>> secret_agent = store.find(SecretAgent).one()
    >>> secret_agent.name, secret_agent.passcode    
    (u'James Bond', u'007')
    >>> teacher = store.find(Teacher).one()
    >>> teacher.name, teacher.school
    (u'Albus Dumbledore', u'Hogwarts')
    >>> secret_agent = store.find(SecretAgent, SecretAgent.name==u'James Bond').one()
    >>> secret_agent.passcode
    u'007'
    >>> teacher = store.find(Teacher, Teacher.school==u'Hogwarts').one()
    >>> teacher.name
    u'Albus Dumbledore'

So we made it by using a metaclass that automatically generate a bunch of attributes.

Mapping inheritance to a RDBMS with storm. Proxy version

Friday, January 23rd, 2009

One problem that we had in the first version of our inheritance by composition pattern was that we could not make storm queries using the subclasses. In other words, the following would return None::

    secret_agent = store.find(SecretAgent, SecretAgent.name==u'James Bond').one()

The reason is that the expresion SecretAgent.name would resolve to a Passthrough lazr.delegates object that Storm does not know how to handle.

This time we will try to fix this problem using a manually generated version of our classes using storm’s Proxy objects.

The interface definitions do not change:

    >>> from zope.interface import Interface, Attribute
    >>> class IPerson(Interface):
    ...     name = Attribute("Name")
    ...
    >>> class ISecretAgent(IPerson):
    ...     passcode = Attribute("Passcode")
    ...
    >>> class ITeacher(IPerson):
    ...     school = Attribute("School")

Neither the Person class:

    >>> from zope.interface import implements
    >>> from zope.interface.verify import verifyClass
    >>> from lazr.delegates import delegates
    >>> from storm.locals import Store, Storm, Unicode, Int, Proxy, Reference
    >>> class Person(Storm):
    ...     implements(IPerson)
    ...
    ...     __storm_table__ = "person"
    ...
    ...     id = Int(allow_none=False, primary=True)
    ...     name = Unicode()
    ...     person_type = Int(allow_none=False)
    ...     _person = None
    ...
    ...     def __init__(self, store, name, person_class, **kwargs):
    ...         self.name = name
    ...         self.person_type = person_class.person_type
    ...         store.add(self)
    ...         self._person = person_class(self, **kwargs)
    ...
    ...     @property
    ...     def person(self):
    ...         if self._person is None:
    ...             assert self.id is not None
    ...             person_class = BasePerson.get_class(self.person_type)
    ...             self._person = Store.of(self).get(person_class, self.id)
    ...         return self._person
    >>> verifyClass(IPerson, Person)
    True

Neither our custom metaclass:

    >>> from storm.properties import PropertyPublisherMeta
    >>> class PersonType(PropertyPublisherMeta):
    ...     def __init__(self, name, bases, dict):
    ...         super(PersonType, self).__init__(name, bases, dict)
    ...         if not hasattr(self, '_person_types_registry'):
    ...             self._person_types_registry = {}
    ...         elif hasattr(self, '__storm_table__'):
    ...             key = len(self._person_types_registry)
    ...             self._person_types_registry[key] = self
    ...             self.person_type = key
    ...
    ...     def get_class(self, person_type):
    ...         return self._person_types_registry[person_type]

Here start the changes. Our BasePerson class does not have the delegates call and does not define the person_id attribute and person reference.

    >>> class BasePerson(Storm):
    ...     __metaclass__ = PersonType
    ...
    ...     def __init__(self, person):
    ...         self.person = person

Instead we define the person_id and person reference in each subclass and also we define each attribute of the Person base class as a proxy to the related attribute of the person reference.

    >>> class SecretAgent(BasePerson):
    ...     implements(ISecretAgent)
    ...
    ...     __storm_table__ = "secret_agent"
    ...     passcode = Unicode()
    ...     person_id = Int(allow_none=False, primary=True)
    ...     person = Reference(person_id, Person.id)
    ...     name = Proxy(person, Person.name)
    ...
    ...     def __init__(self, person, passcode=None):
    ...         super(SecretAgent, self).__init__(person)
    ...         self.passcode = passcode
    >>> verifyClass(ISecretAgent, SecretAgent)
    True

We do it again for the Teacher class:

    >>> class Teacher(BasePerson):
    ...     implements(ITeacher)
    ...
    ...     __storm_table__ = "teacher"
    ...     school = Unicode()
    ...     person_id = Int(allow_none=False, primary=True)
    ...     person = Reference(person_id, Person.id)
    ...     name = Proxy(person, Person.name)
    ...
    ...     def __init__(self, person, school=None):
    ...         super(Teacher, self).__init__(person)
    ...         self.school = school
    >>> verifyClass(ITeacher, Teacher)
    True

Time to test the database storage:

    >>> from storm.locals import create_database
    >>> database = create_database("sqlite:")
    >>> store = Store(database)
    >>> result = store.execute("""
    ...     CREATE TABLE person (
    ...         id INTEGER PRIMARY KEY,
    ...         person_type INTEGER NOT NULL,
    ...         name TEXT NOT NULL)
    ... """)
    >>> result = store.execute("""
    ...     CREATE TABLE secret_agent (
    ...         person_id INTEGER PRIMARY KEY,
    ...         passcode TEXT)
    ... """)
    >>> result = store.execute("""
    ...     CREATE TABLE teacher (
    ...         person_id INTEGER PRIMARY KEY,
    ...         school TEXT)
    ... """)
    >>> secret_agent = Person(store, u"James Bond",
    ...                        SecretAgent, passcode=u"007")
    >>> ISecretAgent.providedBy(secret_agent.person)
    True
    >>> teacher = Person(store, u"Albus Dumbledore",
    ...                  Teacher, school=u"Hogwarts")
    >>> ITeacher.providedBy(teacher.person)
    True
    >>> store.commit()

And what’s more important, all this changes should make possible to do the query with the subclass:

    >>> del secret_agent
    >>> del teacher
    >>> store.rollback()
    >>> secret_agent = store.find(SecretAgent).one()
    >>> secret_agent.name, secret_agent.passcode
    (u'James Bond', u'007')
    >>> teacher = store.find(Teacher).one()
    >>> teacher.name, teacher.school
    (u'Albus Dumbledore', u'Hogwarts')
    >>> secret_agent = store.find(SecretAgent, SecretAgent.name==u'James Bond').one()
    >>> secret_agent.passcode
    u'007'

We have improved the power of the pattern but now it is much more verbose to write each subclass since we need to repeat a lot of things. Note that we can not move the definition of the person_id and person attributes to the BasePerson aux class because Storm will tell us that it lacks the __storm_table__ attribute. In other words: storm does not allow attributes in abstract classes.

Mapping inheritance to a RDBMS with storm and lazr.delegates

Sunday, January 18th, 2009

When using a ORM one of the most common problems is how to map your beautiful
application class inheritance to the database. The specific scenario I’m going
to describe is when you have an abstract base class with some fields and you
want to store those fields in a database table. Then all of its subclasses will
have their own table and to get the data of an instance you will need to make
a join between the base table and the subclass table.

One pattern to accomplish this is the infoheritance pattern described in the
Storm documentation. I’ll show you here a slightly modified version of this
pattern that uses the package lazr.delegates to make the user code easier by
hiding the fact that we are using composition to model inheritance.

So let’s start with some interface definition showing our model hierarchy:

    >>> from zope.interface import Interface, Attribute
    >>> class IPerson(Interface):
    ...     name = Attribute("Name")
    ...
    >>> class ISecretAgent(IPerson):
    ...     passcode = Attribute("Passcode")
    ...
    >>> class ITeacher(IPerson):
    ...     school = Attribute("School")

No rocket science so far. Let’s write now the implementation of the
IPerson interface. This will be our abstract base class. Pay special
attention to the person property which dynamically retrieve the subclass
instance by using composition.

    >>> from zope.interface import implements
    >>> from zope.interface.verify import verifyClass
    >>> from lazr.delegates import delegates
    >>> from storm.locals import Store, Storm, Unicode, Int, Reference
    >>> class Person(Storm):
    ...     implements(IPerson)
    ...
    ...     __storm_table__ = "person"
    ...
    ...     id = Int(allow_none=False, primary=True)
    ...     name = Unicode()
    ...     person_type = Int(allow_none=False)
    ...     _person = None
    ...
    ...     def __init__(self, store, name, person_class, **kwargs):
    ...         self.name = name
    ...         self.person_type = person_class.person_type
    ...         store.add(self)
    ...         self._person = person_class(self, **kwargs)
    ...
    ...     @property
    ...     def person(self):
    ...         if self._person is None:
    ...             assert self.id is not None
    ...             person_class = BasePerson.get_class(self.person_type)
    ...             self._person = Store.of(self).get(person_class, self.id)
    ...         return self._person
    >>> verifyClass(IPerson, Person)
    True

We will also use a custom metaclass (based on Storm metaclass) so it will
automatically register our subclasses. This is necessary for the dynamic
person property of the Person class where we map integer (stored in the
database) to classes (stored in the source code).

    >>> from storm.properties import PropertyPublisherMeta
    >>> class PersonType(PropertyPublisherMeta):
    ...     def __init__(self, name, bases, dict):
    ...         super(PersonType, self).__init__(name, bases, dict)
    ...         if not hasattr(self, '_person_types_registry'):
    ...             self._person_types_registry = {}
    ...         elif hasattr(self, '__storm_table__'):
    ...             key = len(self._person_types_registry)
    ...             self._person_types_registry[key] = self
    ...             self.person_type = key
    ...
    ...     def get_class(self, person_type):
    ...         return self._person_types_registry[person_type]

Now we define a convenience base class for our subclasses. Remember that
the subclasses don’t really inherit from the Person class because we
are using composition. This is where the lazr.delegates.delegates function
comes to rescue. By saying that we delegate the implementation of the
IPerson interface to the ‘person’ attribute, the instances of these subclasses
will look like they really are subclasses of Person, not just from BasePerson.

    >>> class BasePerson(Storm):
    ...     __metaclass__ = PersonType
    ...     delegates(IPerson, "person")
    ...
    ...     person_id = Int(allow_none=False, primary=True)
    ...     person = Reference(person_id, "Person.id")
    ...
    ...     def __init__(self, person):
    ...         self.person = person
    ...
    >>> class SecretAgent(BasePerson):
    ...     implements(ISecretAgent)
    ...
    ...     __storm_table__ = "secret_agent"
    ...     passcode = Unicode()
    ...
    ...     def __init__(self, person, passcode=None):
    ...         super(SecretAgent, self).__init__(person)
    ...         self.passcode = passcode

Here is the magic: we have an interface hierarchy and a different
hierarchy for the classes implementing them. But it’s all transparent
and our classes implement the full hierarchy:

    >>> verifyClass(ISecretAgent, SecretAgent)
    True
    >>> class Teacher(BasePerson):
    ...     implements(ITeacher)
    ...
    ...     __storm_table__ = "teacher"
    ...     school = Unicode()
    ...
    ...     def __init__(self, person, school=None):
    ...         super(Teacher, self).__init__(person)
    ...         self.school = school
    ...
    >>> verifyClass(ITeacher, Teacher)
    True

Now let’s try storing the objects in the database. We will use a
sqlite in memory database for this example.

    >>> from storm.locals import create_database
    >>> database = create_database("sqlite:")
    >>> store = Store(database)
    >>> result = store.execute("""
    ...     CREATE TABLE person (
    ...         id INTEGER PRIMARY KEY,
    ...         person_type INTEGER NOT NULL,
    ...         name TEXT NOT NULL)
    ... """)
    >>> result = store.execute("""
    ...     CREATE TABLE secret_agent (
    ...         person_id INTEGER PRIMARY KEY,
    ...         passcode TEXT)
    ... """)
    >>> result = store.execute("""
    ...     CREATE TABLE teacher (
    ...         person_id INTEGER PRIMARY KEY,
    ...         school TEXT)
    ... """)
    >>> secret_agent = Person(store, u"James Bond",
    ...                        SecretAgent, passcode=u"007")
    >>> ISecretAgent.providedBy(secret_agent.person)
    True
    >>> teacher = Person(store, u"Albus Dumbledore",
    ...                  Teacher, school=u"Hogwarts")
    >>> ITeacher.providedBy(teacher.person)
    True
    >>> store.commit()

The objects are now saved in the database. Let’s destroy them and
retrieve them back using some queries:

    >>> del secret_agent
    >>> del teacher
    >>> store.rollback()
    >>> secret_agent = store.find(SecretAgent).one()
    >>> secret_agent.name, secret_agent.passcode
    (u'James Bond', u'007')
    >>> teacher = store.find(Teacher).one()
    >>> teacher.name, teacher.school
    (u'Albus Dumbledore', u'Hogwarts')

The great thing is that we can write teacher.name without having to
write teacher.person.name (which also works by the way) effectively
hiding the implementation detail of composition.

Just one final note: Bear in mind that you should not have very deep
hierarchies or you may get a lot of JOINs and a slow application.

You can download a couple of files to test this on your own computer. You just need storm 0.14 and lazr.delegates 1.0, both of which can be installed with easy_install:

Conexión a internet desde un móvil Nokia 6234 con Simyo

Sunday, December 14th, 2008

Tras un par de intentos fallidos de conectarme a Internet desde mi móvil con mi nuevo proveedor he conseguido que funcione.

Nokia 6234

Nokia 6234

A continuación escribo las opciones que he tenido que configurar en el móvil para conseguirlo. Espero que la nomenclatura se entienda.

Configuración: Configuración: Ajustes config. personal: Opciones: Añadir nuevo: Internet

  Nombre de cuenta: Internet Simyo
  Página de inicio: http://www.google.com
  Nombre de usuario:
  Contraseña:
  Usar pto. acceso preferido: No
  Conf. de punto de acceso:

    Proxy: Activado
    Dirección de proxy: 217.18.32.181
    Puerto de proxy: 8080
    Portador de datos: Paquetes de datos
    Configuración portador:

      Pto. acceso paquts. datos: gprs-service.com
      Tipo de red: IPv4
      Tipo de autentificación: Normal
      Nombre de usuario:
      Contraseña: 

Internet: Configuración: Ajustes de configuración:

  Configuración: Configuración personal
  Cuenta: Internet Simyo
  Mostrar ventana terminal: No

Para el que esté pensando que eso de internet desde un móvil normalito no tiene mucho sentido pues sí y no. Está claro que cualquier parecido entre navegar con un ordenador y un móvil como el mío es pura coincidencia, pero eso no quiere decir que la posibilidad de ver tu correo en Gmail desde tu móvil no sea útil o también, la posibilidad de sincronizar tus contactos entre el móvil, el ordenador, tu cuenta google, etc. usando servicios como scheduleworld.com

Las tarifas de mi proveedor las podeis consultar en su web y la verdad es que me parecen bastante razonables. Por ahora estoy contento con Simyo no sólo por que me resulta más barato que mi anterior proveedor, si no porque es infinitamente más transparente y claro que los demás y al menos tienes la sensación de que estás pagando por lo que usas, no por lo que ellos quieren.

El siguiente paso ha sido conectar mi Nokia N800 al teléfono vía Bluetooth y usar la conexión a internet del teléfono para navegar desde el otro cacharro. Esto ya se va pareciendo mucho más a navegar a la vieja usanza gracias a la pantalla de 800 pixeles de ancho que tiene el N800.

Nokia N800

Nokia N800

Si mi portátil tuviera Bluetooth, también podría conectarme a internet desde cualquier sitio, pero fui tan listo al comprarlo que desactive esa opción pensando que nunca la usaría. Ahora puedo pedir esa ampliación e instalarla yo mismo o comprar un pequeño dongle usb y hacer lo mismo.

Encoding videos for the Nokia N800

Sunday, November 23rd, 2008

Quick command reminder about how to encode videos for watching them in the Nokia N800:

mencoder Fringe-S01E06.avi -o Fringe-S01E06-n800.avi -oac mp3lame -lavcopts acodec=libmp3lame:abitrate=96 -ovc lavc -lavcopts vcodec=mpeg4:autoaspect:vbitrate=600:vpass=1:turbo -vf scale=400:240 -ffourcc DIVX -idx

Update: add these options to embed subtitles:

-sub Fringe-S01E06.srt -subcp latin5 -subfont-text-scale 4

You will need a subfont.ttf font file in ~/.mplayer/

Y ya van 5

Friday, July 4th, 2008

Escribo este post desde la última charla de la quinta Guadec Hispana. Quién lo diría desde aquel primer encuentro en Almendralejo, pero lo cierto es que hemos pasado ya por La Coruña, Vilanova, Granada y Fuenlabrada. Afortunadamente yo he tenido la suerte de asistir a todas ellas y ya es casi una cita obligada para mí. Más aún cuando sólo he podido ir a la Guadec internacional una vez.

Han sido dos días muy agradables viendo a viejos conocidos como Germán, los Carlos, Álvaro, Palomo, Daniel, Claudio, Roberto, Domingo y muchos otros que posiblemente olvide.

Al igual que GCubo, el grupo de personas de GNOME-Hispano es ya un grupo de amigos primero y de desarrolladores/usuarios de GNOME después. Tristemente, y al igual que GCubo otra vez, cada vez se ven menos caras nuevas. Aquí en la Guadec se ha hablado de esto y se han intentado buscar causas y soluciones sin llegar a un acuerdo concreto.

Al final, para mí no deja de ser un par de días muy agradables en un ambiente distendido y divertido en los que siempre aprendes cosas nuevas pero sobre todo mantienes el contacto con un puñado de personas que vienen todos los años porque les apasiona esto del software libre. Como a mí.

Algunas caras de esta Guadec-es

Libros que leí en el 2007

Thursday, January 17th, 2008

Siguiendo un poco el ejemplo de Malglam, aunque con un poco más de retraso, aquí os dejo la lista de libros que leí el año pasado:

Conan de Cimmeria. Volumen 1. 1932 – 1933

conan-1.jpgConan siempre ha sido uno de mis héroes desde pequeño y aunque no tuviera muchos comics de él, tras ver la película Conan el Bárbaro, siempre que podía imitaba sus mandobles con una fregona. Ahora tengo la edición de coleccionista de la película y estos dos tomos que Ana me ha regalado este año. Lo que no sabía de pequeño es que Robert E. Howard, el autor del personaje, era coetáneo de H. P. Lovecraft, uno de mis autores preferidos. Eso se nota en algunas descripciones y sensaciones que transmiten los relatos de Conan, quién puede matar a un gorila de un puñetazo pero cuando se enfrenta a hechiceros y a lo desconocido en general tiene miedo y prefiere evitarlo. A través de los relatos cortos que componen el libro te haces una idea de la personalizad de Conan: bruto y primitivo pero al mismo tiempo inteligente y justo. Un libro muy recomandable si tienes los 60 eurazos que cuesta esta edición de super lujo :-)

Conan de Cimmeria. Volumen 2. 1933 – 1934

conan-2.jpgMás de lo mismo, es decir, genial. Esta vez hay menos relatos pero son más largos. El último, “La Hora del Dragón”, me ha parecido el mejor relato de Howard de los que he leido. Es casi una novela por su extensión y habla de los días en los que Conan ya era rey de Aquilonia, de cómo le arrebatan el trono y de cómo consigue recuperarlo. Ojalá alguién haga un día una película de este relato.

Añoranzas y Pesares

anoranzas-y-pesares.jpg Añoranzas y pesares es una trilogía compuesta de 4 libros. Es trilogía porque el tercer y cuarto libro originariamente eran uno solo pero por su tamaño las editoriales decidieron dividirlo en dos. Me lo he leido porque Ana me lo ha recomendado y porque en general soy muy aficionado a los libros de fantasía. El libro engancha mucho porque la historia es rápida y dinámica (me leí los 4 libros en dos meses) pero creo que eso es todo lo bueno que puede decir sobre él. Es bastante predecible y algunas cosas parecen copias literales de El Señor de los Anillos pero bueno, junto con Ken Follet o Stephen King, creo que el autor es uno de esos que hacen libros como churros y libros que enganchan mucho.

Paper Prototyping

paper-prototyping.gifEste libro trata de una técnica que me llamaba la atención desde hace algún tiempo: hacer prototipos en papel de programas informáticos. Básicamente viene a decir que es tan poco lo que cuesta hacer un prototipo en papel y tanto lo que se aprende de él que todos los proyectos de software deberían hacerlos en sus fases iniciales. El libro hace especial hincapié en los tests de usabilidad usando prototipos de papel pero yo creo que hacer prototipos de papel es también de enorme utilidad para etapas de análisis y posterior implementación.

Es un buen libro pero quizá excesivamente largo para las 4 o 5 ideas claves que explica. La verdad es que al final se me hizo algo pesado.

User Interface Design for Programmers

ui_for_programmers.jpgEste libro lo leí durante mi estancia en Brasil en la magnifica biblioteca de Async. Me gustó tanto que he decidido comprarlo y releerlo en este año pasado. Como la mayoría de los libros que me gustan, es un libro corto y escrito en un lenguaje informal y muy atractivo, como casi todo lo que escribe Joel. Se basa en la premisa de que los programadores y los usuarios tienen modelos distintos de los programas informáticos y que un programa será tanto más usable cuanto más se acerque su modelo al modelo del usuario. Este concepto tan difuso es explicado con suma claridad en los capítulos del libro, que en total, no me llevaron más de 3 tardes en leerlo.

Don’t make me think

dont-make-me-think.jpgAl igual que el User Interface Design for Programmers, este libro también lo leí en Brasil y también me fascinó. Se lee en el mismo tiempo que se lee un Mortadelo, uno se rie casi igual y se aprende un montón sobre usabilidad de páginas web. Como el anterior, el libro gira en torno a una premisa: cualquier elemento de una página web (o cualquier interfaz de usuario) que haga pensar al usuario y le obligue a tomar una decisión, sobra. En los siguientes capítulos desarrolla esta idea y pone numerosos ejemplos con webs existentes de cosas que se deben hacer y cosas que no se deben hacer. Especial mención merece un apéndice al final del libro donde encontramos una carta modelo para tu jefe o tu cliente explicándo por qué no se deben hacer páginas web con gifs animados, introducciones en flash y demás aberraciones que sólo podemos perdonarle a Homer Simpson.

The C Programming Language

the-c-programming-language.jpgHe de confesar que a estas alturas de la vida no había leído este libro y tenía una mezcla de curiosidad y mala conciencia por ello. Afortunadamente ha sido fácil de remediar y he de decir que el libro no me ha decepcionado lo más mínimo, cosa que suele pasarme por ejemplo con ciertas películas, que todo el mundo recomienda y luego la ves y dices “no es para tanto”. Pienso que este libro debería ser de obligada lectura en la carrera de informática ya que explica de forma clara y cristalina conceptos difíciles de coger la primera vez que empiezas a programar como los arrays, las cadenas de caractéres, los punteros, etc. Lo único que me falta para completar esta lectura es desarrollar un programilla sencillo pero útil donde pueda poner en práctica lo que he aprendido y/o recordado con este libro.

The Mythical Man Month

the-mythical-man-month.jpgEste es el tercer y último libro de este post de los que leí en Brasil. Es considerado un clásico en la ingeniería del software y comprende un montón de artículos sobre el desarrollo de aplicaciones software de complejidad y tamaño considerables. En él viene a decir que la tarea más compleja de hacer una aplicación es la comunicación entre las distintas partes involucradas: el cliente, el arquitecto de software, los analistas, los programadores, etc. A consecuencia de esto añadir más mano de obra a un proyecto de software que lleva retraso según la planificación original no sólo no resuelve el problema sino que lo agrava. Otro artículo interesante incluido en el libro es “No silver bullet” en el que viene decir que en la informática no hay una herramienta/tecnología/metodología mágica que mejore sustancialmente la creación de software tal y como han ido vendiendola distintos fabricantes desde finales de los años 60. Es curioso (o aterrador si se quiere) comprobar que casi 40 años después, este paper sigue siendo tan verídico como en la fecha en la que se publicó. Lo de silver bullet (bala de plata) es porque compara el proceso de creación de software con un hombre lobo por los peligros que ello conlleva y la bala de plata es lo único que mata al hombre lobo. En informática no hay balas de plata.

El tío Petros y la conjetura de Goldbach

tio_petros.jpgEsta novela la ví comentada en barrapunto y un día que estaba en Alcampo, estaba en la sección de novedades y me hice con ella. Es un libro fácil de leer y bastante realista. La verdad es que me costaba creer que fuera una novela en lugar de una biografía y estoy seguro de que está inspirada/basada en la vida de un célebre matemático. La historía trata la vida de un matemático griego con una capacidad extraordinaria que dedica su vida a resolver la conjetura de Goldbach todo contado desde la perspectiva de su sobrino, el verdadero protagonista del libro. No cuento más detalles para no fastidiarle el libro a nadie. En definitiva, es un libro ameno y muy interesante.

Snow Crash

snow-crash.jpgSnow Crash se considera uno de los libros que iniciaron el género de Ciber Punk. Tiene un estilo ágil y rápido con las descripciones justas y diálogos llenos de dobles sentidos y argot. Esto hace que se lea muy rápido pero al mismo tiempo requiere concentración por parte del lector para que no se le pase ningún detalle de la enrevesada trama. Su visión del futuro no es muy tentadora pero su gran dosis de humor negro y cinismo hace que al final sea una experiencia divertida, por lo menos al leerla. Vivir en ese mundo me imagino que y no es tán divertido. La portada de mi edición es la de la foto y es bastante más cutre: una chica en 3D encima de una patineta voladora. Es bastante dificil que te tomen en serio cuando te ven en el autobus leyendo un libro con dicha portada….

Hegemonía o Supervivencia. La estrategia imperialista de Estados Unidos

hegemonia-o-supervivencia.jpgEste libro me lo regalaron Mario y Montero el año pasado y es un poco denso de lee, lleno de referencias a otros libros, de cifras y estadísticas. Todo para poner a Estados Unidos en su lugar. Después de leer el libro lo único que se te queda es una sensación de mala leche e impotencia enorme tras ver que todas tus sospechas sobre este país eran ciertas y Chomsky simplemente las ha investigado y plasmado aquí. No apto para personas sensibles a las injusticias mundiales.

El ecologista escéptico

el-ecologista-esceptico.jpgEste libro me lo recomendó mi buen amigo Jaime, el escéptico por excelencia :-) He decir que aún no lo he terminado porque si bien el de Chomsky era denso esté es más compacto que un mantecao de maritoñis. Lo bueno es que esta dividido en distintas partes y puedes leerlas en el orden que quieras porque son más o menos independientes excepto la primera que es la introducción y que es la que deberías leer primero. El libro viene a decir básicamente que los medios de comunicación tienden a darnos malas noticias sobre el mundo y que las buenas casi nunca nos llegan. Así es normal que siempre estemos en estado de alerta y paranoia esperando que llegue el siguiente cataclismo. El autor insiste en que es necesario hacer un análisis detallado de los problemas que asolan el mundo (porque haberlos haylos, eso está claro) para poder decidir en qué emplear nuestros (escasos) recursos de la mejor forma posible. No creo que nadie pueda estar en contra de está idea tan racional.

The Alphabet of Manliness

alphabet-manliness.jpgEl alfabeto de la masculinidad es un libro escrito por el autor de la mejor página del universo y que no te decepcionará. Por favor, abstenganse las mujeres en general y las feministas en particular porque el libro es muy politicamente incorrecto. Cada letra del alfabeto la asocia con un sígno claro de la masculinidad. Algunos ejemplos son la H de Heavy Metal, la C de Costillas de Cerdo, la T de tetas o la P de patada en el culo. Como se puede ver, todos ellos claros símbolos de masculinidad. Si te gustaron las frases de Chuck Norris, este libro te encatará. El que quiera saber más, el libro tiene hasta su propia web.

Los Hijos de Húrin

hijos-hurin.jpgPor último, este año pasado me leí los Hijos de Hurín, de Tolkien padre aunque editado y juntado por Tolkien hijo. He de decir que he leido más de un libro de los que ha publicado Tolkien hijo y sólo este me ha parecido bueno. El Libro de los Cuentos Perdidos, el Retorno de la Sombra y otros como estos me parecieron un mero trabajo de corta y pega. Pero en esta ocasión parece que se ha esmerado. La historia que cuenta no es nueva si has leido el Silmarilion, eso sí esta mucho más desarrollada y se puede leer sin tener que memorizar 50 nombres para no perderte. La gente que lee el Silmarilion y no les gusta porque esperan que sea otro Señor de los Anillos se sentirán un poco menos decepcionados con este libro. Aunque la verdad, a mí el Silmarilion me encantó. Este libro me ha gustado tanto que lo he comprado 3 veces este año: uno para mí y dos para hacer regalos, a Ana y a Daniel, las otras dos personas en el mundo que conozco que están casi tan flipadas con Tolkien como yo.

An address form

Tuesday, November 20th, 2007

In the Zope 3 app I’m working at we have person objects that can have a list of addresses associated to them. No rocket science so far. So I needed to create an add and an edit forms for this. Something with url like these:

  • http://yourhost/app/people/john/addresses/+/@@addAddress.html
  • http://yourhost/app/people/john/addresses/3/@@editAddress.html

Now you wonder how an address looks like. Quite simple, let’s look at its interface:

class IAddress(IContained):

    line = zope.schema.Text(

        title=u'Line',

        description=u'Street type and number information',

        required=True

    )
    country = zope.schema.Choice(

        title=u'Country',

        description=u'Country',

        vocabulary='CountriesVocabulary',

        required=True,

    )

    state = zope.schema.Choice(

        title=u'State',

        description=u'State',

        vocabulary='StatesVocabulary',

        required=False,

    )

    postalCode = zope.schema.Choice(

        title=u'Postal Code',

        description=u'Postal Code and City',

        vocabulary=u'PostalCodesVocabulary',

        required=False,

    )

    contact = zope.schema.TextLine(

        title=u'Contact',

        description=u'Contact information',

        required=False

    )

    notes = zope.schema.Text(

        title=u'Notes',

        description=u'Other notes',

        required=False

    )

As you can see the country, state and postal code are choices taken from different vocabularies. I have models for those objects and the structure is hierarchical: A country contains state and a state contains postal codes.

I could just store the postal code inside the address since I can retrieve its state and its country just from the postal code. We decided not to do so to because of two reasons:

  • To keep our queries and business logic simpler. For example, consider you want a report of all your customer living in Spain…
  • So we could use the hierarchical relationships to aid our users in the addresses forms.

I’ll explain the second reason in more detail in this post. What I wanted to accomplish was something like what you see in this small screencast:

addres-form-screncast.gif

As you see, the user first select the country in the first dropdown list, this will fill the state dropdown list with all the states belonging to that country. Similarily, when the user chooses a state the postal codes
dropdown list will be filtered.

I started implementing this with the wrong approach which I will also describe here for the record.

Wrong approach

In Zope 3 a choice field gets it list of possible values from something called a vocabulary (or more recently, a source). This can be anything that returns a list of terms. In our case the country vocabulary will
get the list of country objects from the database. I have a countries folder registered with an ICountries interface so the task of getting the list of country objects is quite easy:

class CountriesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        for name, countries in zope.component.getUtilitiesFor(ICountries):
            terms += [SimpleTerm(country, country.__name__, country.name)
                      for country in countries.values()]
        super(CountriesVocabulary, self).__init__(terms)

Building the states and postal codes vocabularies is a little more difficult since they depend on a context. This mean that the states vocabulary will depend on a specific country and the postal codes vocabulary will depend on a specific state. But the context won’t be the country neither the state in this two cases but the address object since the vocabularies are used in fields of the IAddress interface. Using this idea I coded these vocabularies:

class StatesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        if IAddress.providedBy(context):
            country = IAddress(context).country
            if country:
                terms = [SimpleTerm(state, state.__name__, state.name)
                         for state in country.values()]

        super(StatesVocabulary, self).__init__(terms)

class PostalCodesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        if IAddress.providedBy(context):
            state = IAddress(context).state
            if state:
                terms = [SimpleTerm(pc,
                                    pc.__name__,
                                    u'%s - %s' % (pc.code, pc.city))
                         for pc in state.values()]
        super(PostalCodesVocabulary, self).__init__(terms)

So far so good but here is my problem: when you create or edit an address object you need to hit the save button three times to store the country, state and postal code. Why is this? Let’s try to reproduce these three steps:

  1. Step 1: You select a country and save the address
  2. Step 2: Now the states vocabulary will be filled with the list of states for the country you choosed in step 1
  3. Step 3: Finally you can choose a postal code from the postal codes of the state you choosed in step 2.

Note that until you saved the country the vocabulary for states won’t have that information and thus, will return an empty term list. Same thing happens with the postal codes.

Even if you can get the proper information using AJAX in the form and fill the dropdown lists with the right information you won’t be able to save the address object since the vocabularies are also used for validation
purposes.

No need to say this was a pain in the ass and kepts my brain busy for a few days until I found the right solution.

Right approach

The lesson learned from the previous approach was that something was wrong with dictionaries which depended on a context in such a strict way. In the IAddress interface I should keep the fields simple enough to let the form set any state on the state field and any postal code in the postal code
field. As I still want some integrity in my data it’s time to delegate that to an invariant. In other words, I will any value of the right type into the state and postal code attributes and after that I will validate these
fields with an invariant that will make sure the state is inside the country and the postal code is inside the state. An invariant like this:

def postalCodeInsideStateInsideCountry(address):
    country = address.country
    state = address.state
    postalCode = address.postalCode
    if country is not None and state is not None:
        if state not in country.values():
            st = state.name or state.__name__
            co = country.name or country.__name__
            raise zope.schema.ValidationError(
                u"The state %s does not belongs to country %s" % (st, co)
                )

        if postalCode is not None:
            if postalCode not in state.values():
                pc = postalCode.code or postalCode.__name__
                st = state.name or state.__name__
                raise zope.schema.ValidationError(
                    u"The postal code %s does not belongs to state %s" % (pc, st)
                    )

Then I just add this declaration inside the IAddress interface:

class IAddress(IContained):
    ...

    zope.interface.invariant(postalCodeInsideStateInsideCountry)

Next I’ll have to rewrite my vocabularies to be context-free and return the full list of objects in each case:

class PostalCodesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        for name, countries in zope.component.getUtilitiesFor(ICountries):
            for country in countries.values():
                for state in country.values():
                    prefix = country.__name__ + '/' + state.__name__ + '/'
                    terms += [SimpleTerm(RSP(pc),
                                         prefix + pc.__name__,
                                         u'%s - %s' % (pc.code, pc.city))
                              for pc in state.values()]

        super(PostalCodesVocabulary, self).__init__(terms)

class StatesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        for name, countries in zope.component.getUtilitiesFor(ICountries):
            for country in countries.values():
                terms += [SimpleTerm(RSP(state),
                                     country.__name__ + '/' + state.__name__,
                                     state.name)
                          for state in country.values()]

        super(StatesVocabulary, self).__init__(terms)

You may note that the token of each term has a prefix now. This is because the token should be unique inside that vocabulary. I’m using the country code and the state code with a slash separating them because I will use
this token later in javascript.

This fixed my problem as now I’m able to create an address object with just a save button hit without losing data integrity but I still have one more problem: my forms list all states and postal codes no matter which
country is selected in the case of states and what state is selected in the case of postal codes. Seems like all these efforts didn’t help me to accomplish what I initially wanted.

It’s time for some javascript to make things truly dynamic.

Adding javascript for a richer user experience

My solution was to add a small jQuery script and a couple of related views to fill the dropdown lists every time the user changes them. This mean that if the user selects a country, an ajax request will be made to retrieve the list of states for that country and will populate the state select tag with those options. Similar behaviour happens when the user changes the state.

Let’s see the jQuery code:

(function($){

$(document).ready(function () {

    function fillSelect(data) {
        var options = $.map(data, function (obj, index) {
            return '<option value="' + obj.id + '">' + obj.name + '</option>';
        });
        return '<option value="">(no value)</option>n' + options.join("n");
    }

    $("select#form.country").change(function () {
        var value = $(this).val();
        if (value) {
            var currentState = $("select#form.state").val();
            var url = '../../Countries/' + value + '/@@states.json';
            $.getJSON(url, function (data) {
                $("select#form.state")
                  .html(fillSelect(data))
                  .val(currentState)
                  .change();
            });
        } else {
            $("select#form.state").html(fillSelect([])).change();
        }
    });

    $("select#form.state").change(function () {
        var value = $(this).val();
        if (value) {
            var currentPostalCode = $("select#form.postalCode").val();
            var url = '../../Countries/' + value + '/@@postalCodes.json';
            $.getJSON(url, function (data) {
                $("select#form.postalCode")
                  .html(fillSelect(data))
                  .val(currentPostalCode);
            });
        } else {
            $("select#form.postalCode").html(fillSelect([]));
        }
    });

    /* initialize combos */
    $("select#form.country").change();
});

})(jQuery);

Final thoughts

The last bit of love that this form need is some support for adding countries/states/postalCodes when the user is filling an address and that information is not yet in the database. It shouldn’t be too hard to add some javascript buttons that ask the user for that and post it to the server. Then update the selects and let the user choose the new created object.