Arbitrary point checkpoint commit.  Take no notice.
diff --git a/Demo/metaclasses/Eiffel.py b/Demo/metaclasses/Eiffel.py
new file mode 100644
index 0000000..e3efa7f
--- /dev/null
+++ b/Demo/metaclasses/Eiffel.py
@@ -0,0 +1,113 @@
+"""Support Eiffel-style preconditions and postconditions.
+
+For example,
+
+class C:
+    def m1(self, arg):
+	require arg > 0
+	return whatever
+        ensure Result > arg
+
+can be written (clumsily, I agree) as:
+
+class C(Eiffel):
+    def m1(self, arg):
+	return whatever
+    def m1_pre(self, arg):
+	assert arg > 0
+    def m1_post(self, Result, arg):
+	assert Result > arg
+
+Pre- and post-conditions for a method, being implemented as methods
+themselves, are inherited independently from the method.  This gives
+much of the same effect of Eiffel, where pre- and post-conditions are
+inherited when a method is overridden by a derived class.  However,
+when a derived class in Python needs to extend a pre- or
+post-condition, it must manually merge the base class' pre- or
+post-condition with that defined in the derived class', for example:
+
+class D(C):
+    def m1(self, arg):
+	return whatever**2
+    def m1_post(self, Result, arg):
+	C.m1_post(self, Result, arg)
+	assert Result < 100
+
+This gives derived classes more freedom but also more responsibility
+than in Eiffel, where the compiler automatically takes care of this.
+
+In Eiffel, pre-conditions combine using contravariance, meaning a
+derived class can only make a pre-condition weaker; in Python, this is
+up to the derived class.  For example, a derived class that takes away
+the requirement that arg > 0 could write:
+
+    def m1_pre(self, arg):
+	pass
+
+but one could equally write a derived class that makes a stronger
+requirement:
+
+    def m1_pre(self, arg):
+	require arg > 50
+
+It would be easy to modify the classes shown here so that pre- and
+post-conditions can be disabled (separately, on a per-class basis).
+
+A different design would have the pre- or post-condition testing
+functions return true for success and false for failure.  This would
+make it possible to implement automatic combination of inherited
+and new pre-/post-conditions.  All this is left as an exercise to the
+reader.
+
+"""
+
+from Meta import MetaClass, MetaHelper, MetaMethodWrapper
+
+class EiffelMethodWrapper(MetaMethodWrapper):
+
+    def __init__(self, func, inst):
+	MetaMethodWrapper.__init__(self, func, inst)
+	# Note that the following causes recursive wrappers around
+	# the pre-/post-condition testing methods.  These are harmless
+	# but inefficient; to avoid them, the lookup must be done
+	# using the class.
+	try:
+	    self.pre = getattr(inst, self.__name__ + "_pre")
+	except AttributeError:
+	    self.pre = None
+	try:
+	    self.post = getattr(inst, self.__name__ + "_post")
+	except AttributeError:
+	    self.post = None
+
+    def __call__(self, *args, **kw):
+	if self.pre:
+	    apply(self.pre, args, kw)
+	Result = apply(self.func, (self.inst,) + args, kw)
+	if self.post:
+	    apply(self.post, (Result,) + args, kw)
+	return Result
+    
+class EiffelHelper(MetaHelper):
+    __methodwrapper__ = EiffelMethodWrapper
+
+class EiffelMetaClass(MetaClass):
+    __helper__ = EiffelHelper
+
+Eiffel = EiffelMetaClass('Eiffel', (), {})
+
+
+def _test():
+    class C(Eiffel):
+	def m1(self, arg):
+	    return arg+1
+	def m1_pre(self, arg):
+	    assert arg > 0, "precondition for m1 failed"
+	def m1_post(self, Result, arg):
+	    assert Result > arg
+    x = C()
+    x.m1(12)
+    x.m1(-1)
+
+if __name__ == '__main__':
+    _test()
diff --git a/Demo/metaclasses/Enum.py b/Demo/metaclasses/Enum.py
index 71a8e52..e1ae695 100644
--- a/Demo/metaclasses/Enum.py
+++ b/Demo/metaclasses/Enum.py
@@ -1,4 +1,8 @@
-"""Enumeration metaclass."""
+"""Enumeration metaclass.
+
+XXX This is very much a work in progress.
+
+"""
 
 import string
 
diff --git a/Demo/metaclasses/Meta.py b/Demo/metaclasses/Meta.py
new file mode 100644
index 0000000..b63f781
--- /dev/null
+++ b/Demo/metaclasses/Meta.py
@@ -0,0 +1,106 @@
+"""Generic metaclass.
+
+XXX This is very much a work in progress.
+
+"""
+
+import types
+
+class MetaMethodWrapper:
+
+    def __init__(self, func, inst):
+	self.func = func
+	self.inst = inst
+	self.__name__ = self.func.__name__
+
+    def __call__(self, *args, **kw):
+	return apply(self.func, (self.inst,) + args, kw)
+
+class MetaHelper:
+
+    __methodwrapper__ = MetaMethodWrapper # For derived helpers to override
+
+    def __helperinit__(self, formalclass):
+	self.__formalclass__ = formalclass
+
+    def __getattr__(self, name):
+	# Invoked for any attr not in the instance's __dict__
+	try:
+	    raw = self.__formalclass__.__getattr__(name)
+	except AttributeError:
+	    try:
+		_getattr_ = self.__dict__['_getattr_']
+	    except KeyError:
+		raise AttributeError, name
+	    return _getattr_(name)
+	if type(raw) != types.FunctionType:
+	    return raw
+	return self.__methodwrapper__(raw, self)
+
+class MetaClass:
+
+    """A generic metaclass.
+
+    This can be subclassed to implement various kinds of meta-behavior.
+
+    """
+
+    __helper__ = MetaHelper		# For derived metaclasses to override
+
+    __inited = 0
+
+    def __init__(self, name, bases, dict):
+	if dict.has_key('__getattr__'):
+	    raise TypeError, "Can't override __getattr__; use _getattr_"
+	self.__name__ = name
+	self.__bases__ = bases
+	self.__realdict__ = dict
+	self.__inited = 1
+
+    def __getattr__(self, name):
+	try:
+	    return self.__realdict__[name]
+	except KeyError:
+	    for base in self.__bases__:
+		try:
+		    return base.__getattr__(name)
+		except AttributeError:
+		    pass
+	    raise AttributeError, name
+
+    def __setattr__(self, name, value):
+	if not self.__inited:
+	    self.__dict__[name] = value
+	else:
+	    self.__realdict__[name] = value
+
+    def __call__(self, *args, **kw):
+	inst = self.__helper__()
+	inst.__helperinit__(self)
+	try:
+	    init = inst.__getattr__('__init__')
+	except AttributeError:
+	    init = lambda: None
+	apply(init, args, kw)
+	return inst
+    
+
+Meta = MetaClass('Meta', (), {})
+
+
+def _test():
+    class C(Meta):
+	def __init__(self, *args):
+	    print "__init__, args =", args
+	def m1(self, x):
+	    print "m1(x=%s)" %`x`
+    print C
+    x = C()
+    print x
+    x.m1(12)
+    
+
+if __name__ == '__main__':
+    _test()
+
+    
diff --git a/Demo/metaclasses/Trace.py b/Demo/metaclasses/Trace.py
index ed3944f..a5b765a 100644
--- a/Demo/metaclasses/Trace.py
+++ b/Demo/metaclasses/Trace.py
@@ -1,6 +1,10 @@
-"""Tracing metaclass."""
+"""Tracing metaclass.
 
-import types
+XXX This is very much a work in progress.
+
+"""
+
+import types, sys
 
 class TraceMetaClass:
     """Metaclass for tracing.
@@ -28,7 +32,7 @@
 	except KeyError:
 	    for base in self.__bases__:
 		try:
-		    return getattr(base, name)
+		    return base.__getattr__(name)
 		except AttributeError:
 		    pass
 	    raise AttributeError, name
@@ -106,12 +110,15 @@
 
 
 def _test():
-    import sys
+    global C, D
     class C(Traced):
 	def __init__(self, x=0): self.x = x
 	def m1(self, x): self.x = x
 	def m2(self, y): return self.x + y
-    C.__trace_output__ = sys.stdout
+	__trace_output__ = sys.stdout
+    class D(C):
+	def m2(self, y): print "D.m2(%s)" % `y`; return C.m2(self, y)
+	__trace_output__ = None
     x = C(4321)
     print x
     print x.x
@@ -122,5 +129,17 @@
     print x.m2(4000)
     print x.x
 
+    print C.__init__
+    print C.m2
+    print D.__init__
+    print D.m2
+
+    y = D()
+    print y
+    print y.m1(10)
+    print y.m2(100)
+    print y.x
+
 if __name__ == '__main__':
     _test()
+