[PEAK] Trellis API rollout plan

Phillip J. Eby pje at telecommunity.com
Tue Apr 8 22:47:44 EDT 2008


So, at this point, I have a mostly-baked implementation of the new 
Trellis API, minus laziness and connect/disconnect support.  It's 
working side by side with the old API, but I haven't checked it in yet.

Here's what I'm planning to do, more or less in order:

* add laziness and verify that 'compute' rules do not write anything
* add deprecation warnings for the old API
* check in the changed code
* port the Chandler "rearchitecture" branch code to use the new API
* write a porting guide for others to use
* update the Trellis tutorial to reflect the changes
* issue an interim release (0.7a1?) and encourage everyone to move to 
the new API (since code using the old API will be spewing warnings)
* add connect/disconnect support
* drop support for the old API
* issue a new release (0.7a2?) with connector support and without the old API
* Start experimenting with using the new connector stuff for 
functional GUI integration, and resume experimenting with SQLAlchemy 
integration.

Basically, this means that fairly soon you will start getting 
deprecation warnings if you're working from an SVN version of 
Trellis, and until I get a porting guide together, you're going to 
have to look to the changes I've made in SVN as a guide.  Here's a 
quick-and-dirty reference for your convenience:

variable(initially=NO_VALUE, resetting_to=NO_VALUE):
     * value(X)    -> variable(initially=X)
     * receiver(X) -> variable(resetting_to=X)

variable.attributes(**):
     * values(**) -> variable.attributes(**)

variable.attributes.resetting_to(**):
     * receivers(**) -> variable.attributes.resetting_to(**)

perform(rule=None, optional=False):
     * observer(X) -> perform(X)
     * @observer X -> @perform X
     * @optional @observer X -> @perform(optional=True) X

Those are the easy translations, because they're 1:1.  For existing 
uses of 'rule', 'discrete', and 'optional', it's a bit tougher, 
because they will become either 'compute' or 'maintain', depending on 
the context.

If you have a rule with no side-effects, you should use 'compute', 
and if your rule has side-effects, you should use 'maintain':

compute(rule=None, initially=NO_VALUE, resetting_to=NO_VALUE, writable=False):
maintain(rule=None, initially=NO_VALUE, resetting_to=NO_VALUE, optional=False):

'compute' rules are always optional (i.e., not activated until 
needed), and 'maintain' rules are always writable (i.e., the 
attribute can be set).  Both APIs can use 'initially' or 
'resetting_to' in order to set an initial value or make the rule 
discrete (i.e., automatically resetting after a change).

If you don't pass in a rule, the API acts as a decorator, and can be 
used as in these examples:

     @trellis.compute
     def some_rule(self):
         ...

     @trellis.maintain(initially=42):
     def another_rule(self):
         ...

     some_attr = trellis.compute(lambda self: {})

etc.

'compute' rules will be lazily recomputed, in that they will not be 
re-run unless some other rule is actively subscribed to its 
output.  (Attempting to read the rule's value will trigger 
recalculation if the value is out of date, however.)  This, combined 
with the lazy initialization of compute rules, means that compute 
rules will be of generally lower overhead than 'maintain' rules, 
which must always be re-run when a dependency changes (because the 
rule might have side-effects).

To replace the 'rules()' API, there will be two new variations:

compute.attributes(**)
maintain.attributes(**)

Note also that in the past, you could combine rules() and values() 
definitions for the same attribute, but that will not be possible 
with the new API.  A given attribute now has to be defined in exactly 
one place.  If you were previously defining both a rule and value for 
an attribute, you will need to either use maintain(initially=val), or 
compute(initially=val, writable=True) to define the rule.

Inheritance of attribute metadata has also changed; instead of 
querying metadata registries, you can simply refer to 
'SomeBaseClass.some_attr.rule' to retrieve the rule for 'some_attr' 
in SomeBaseClass'.

At this point, this is a very early draft, and it's possible that 
during the remaining porting of the tests and the Chandler rearch 
branch I'll want to tweak these APIs in some way.  This is just a 
snapshot based on what I have in my local checkout right now.




More information about the PEAK mailing list