E&S CVS Commit: pylib - Callback-driven, "push" dependencies, a sane event model, and an

pje at eby-sarna.com pje at eby-sarna.com
Wed Jan 2 00:58:00 EST 2002

Module Name:	pylib
Committed By:	pje
Date:		Wed Jan  2 05:57:29 UTC 2002

Modified Files:
	pylib/TW: Builders.py Components.py Interfaces.py __init__.py
	pylib/TW/Database: DataModel.py
	pylib/TW/tests: Components.py

Log Message:
Callback-driven, "push" dependencies, a sane event model, and an
end to the previous peculiarities of postprocessors!  Plus syntactic
sugar for hooking phase callbacks from builders, and more.

Postprocessor handling is now part of the 'IParentBuilder' interface,
through a new method 'registerPostprocessor()'.  Registering a builder
as a postprocessor means that it will be treated as being dependent on
all sibling builders which are not themselves postprocessors or dependent
on postprocessors.  Postprocessors, in other words, depend on anything
which does not depend on them.  :)  This made unnecessary the ugly hack I
had in 'Database.DataModel' to do an 'Eval' on the result of a
postprocessor.  Any builder such as an 'Eval' which depends on a
postprocessor will automatically follow it, and the postprocessor will not
depend on it.

'AbstractBuilder' is shaping up into a nice little base class, now with a
nested utility class 'hooks' which can be used to set up callbacks
automatically when a builder is added to a build tree.  I'll have to add
some docstrings to actually describe how that works, though.  For right
now, it's UTSL (Use The Source, Luke!) all the way.

The build callbacks/phases have now stabilized into something both stable
and relatively obvious: 'beforeBuild', 'beforeSubcomponents',
'afterSubcomponents', and 'afterBuild'.  Simple, symmetrical, useful, but
still not obvious.  Again, I've gotta document them, but probably not
tonight.  :)

Dependencies are now push-driven; builders can report local dependencies
to their parent builders at any time up through their immediate parent's
'beforeSubcomponents' event.  However, dependencies to a non-sibling
builder must be reported by the end of the lowest common parent's
'beforeSubcomponents' event for all dependencies to be handled properly.
This implies that to be fully general, a builder that can't report
dependencies when added to the build tree should report its dependencies
during the root 'beforeSubcomponents' event.  'Eval()' does this,
since it can't be sure it knows how its referenced names will be

This eliminates the last of the major eccentricities of the kernel.
The only remaining limitation of note is that 'copyIntoSubclasses' may
not work properly when used on a ComponentBuilder.  So far I have no
need to have this sort of "fractal inheritance", but if I or someone
else does in future I'll need to re-examine a few things.  First,
ComponentBuilder isn't really a correct implementation of IBuilder at
present: it doesn't support 'copy()', for instance!  Second, creating
new ComponentBuilders during the root 'beforeBuild' phase would cause
them to subscribe to a callback list *while it was executing*.  This
would probably work, but it makes me a little uneasy to rely on it.
But those are really pretty minor nits, and probably straightforward
to fix.

Misc. other changes...  Stuff moved around in Components.py, trying to
get a little more order to ComponentBuilder's methods.  'IRootBuilder'
is no more; it turns out that the new before/after events can be
considered uniform among all builders.  Other changes to interfaces
have occurred, to support the new dependency model.

This is probably the last major refactoring codewise, but there will
probably be a few cleanup and documentation passes yet to go, perhaps
some minor refitting of methods, probably mostly private ones.  I may
also try to get rid of or redo 'getSubclassRecipes()' and 'getPathFor()'
as they are annoyingly unencapsulated, and poorly explained.  These
changes will likely be very minor in impact, however, compared to what
I've been doing so far.

I also have some performance concerns, given that the UML metamodel
takes 3-4 seconds to build.  Although it's a complex model, I'm not sure
the performance will scale well to really large models used in transient
programs (e.g. command-line tools, as opposed to longer-running
"server"-type processes).  Since build overhead is only at program
startup, most apps can probably pay the price for now.  In future I may
want to find a way to "compile" builds so that the cost is only paid when
a program or its configuration changes.

To view diffs of this commit, you can use the following URL(s):

To generate a diff of this commit:
cvs rdiff -r1.23 -r1.24 pylib/TW/Builders.py
cvs rdiff -r1.35 -r1.36 pylib/TW/Components.py
cvs rdiff -r1.10 -r1.11 pylib/TW/Interfaces.py
cvs rdiff -r1.8 -r1.9 pylib/TW/__init__.py
cvs rdiff -r1.6 -r1.7 pylib/TW/Database/DataModel.py
cvs rdiff -r1.7 -r1.8 pylib/TW/tests/Components.py

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

More information about the source-changes mailing list