Code review comment for lp:~leonardr/lazr.restful/multiversion-rename-params

Revision history for this message
Leonard Richardson (leonardr) wrote :

This branch continues my progress towards making all the named operation annotations work in a multi-versioned environment. This branch gets @rename_parameters_as to work by radically simplifying the BleedThroughDict data structure.

Since BleedThroughDict has only been around for a couple days, I'll explain how it works. It's a stack of dicts that acts like a single dict. It's used to gather annotations in a multi-versioned environment: the 1.0 annotations all go into a dict at the bottom of the stack, the 2.0 annotations go into a dict on top of that, the 3.0 annotations go into a dict on top of _that_, and so on.

Annotations for version n+1 are inherited from n unless redefined for version n. For instance, if the name of the method being published as a named operation is 'foo', but in the definition of version 2.0 there's an @export_operation_as("bar"), then the name of the operation is 'foo' (the default) in 1.0, but 'bar' in 2.0 and 3.0.

My original plan was that each dict would only contain the annotations specific to that version, and inheritance would be implemented by moving down the stack until I found the version that defined the appropriate annotation. In the example above, the stack would look like this:

[(3.0, {}),
 (2.0, {'as' : 'bar'}),
 (1.0, {}]

This is elegant, but it only works for annotations that add objects to the annotation dict. The @rename_parameters_as annotation takes an object already in the dict and modifies its __name__ attribute in place. This means that if you have @rename_parameters_as annotations anywhere in your definition, the last one takes precedence, and modifies the name of that parameter for every single version.

So I changedBleedThroughDict to get the same basic behavior in a much cruder way. When you push a new dict onto the stack, it's initialized with a deep copy of the dict that was originally the top of the stack. In the example above, the stack would look like this:

[(3.0, {'as' : 'bar'}),
 (2.0, {'as' : 'bar'}),
 (1.0, {}]

Now a 2.0 @rename_parameters_as will modify only the copy of the parameter objects found on the 2.0 level of the stack. It won't affect the objects on the 1.0 level. The 3.0 level will inherit the change made on the 2.0 level (thanks to the deep copy), but it it contains its own @rename_parameters_as, that declaration won't affect the 2.0 or the 1.0 levels.

The new BleedThroughDict is not nearly as flexible as the old, but we don't need that flexibility. We always define versions in ascending order and we never go back to modify an old version once it's defined.

I'm entertaining ideas about new names for BleedThroughDict, but I think the name is still appropriate (it's just that the bleeding through happens all at once, not whenever you do a lookup).

« Back to merge proposal