diff pyink/trait.py @ 1348:22a79dcbaec6

Change structure of provide_traits and method_map_traits
author Thinker K.F. Li <thinker@codemud.net>
date Sat, 12 Feb 2011 19:22:21 +0800
parents aaa88d805aac
children b0e54ae756f8
line wrap: on
line diff
--- a/pyink/trait.py	Sat Feb 12 18:21:16 2011 +0800
+++ b/pyink/trait.py	Sat Feb 12 19:22:21 2011 +0800
@@ -4,6 +4,10 @@
 # attributes of the instance of the composition class.
 #
 class require(object):
+    def __init__(self, trait_clazz):
+        self.trait_clazz = trait_clazz
+        pass
+    
     def __get__(self, instance, owner):
         if not instance:        # from a class object
             return self
@@ -32,7 +36,7 @@
         if value != require:
             continue
 
-        require_o = require()
+        require_o = require(trait_clazz)
         setattr(trait_clazz, attr, require_o)
         attrname_map[require_o] = attr
         pass
@@ -69,13 +73,20 @@
 ## \brief Derive and modify an existing trait.
 #
 def derive_trait(a_trait, composite_clazz):
+    #
+    # Set a map mamping requires to attribute names.
+    #
+    # Search provide_traits for requires of a_trait, and patch
+    # attrname_map for it.
+    #
     attrname_map = None
     if hasattr(composite_clazz, 'provide_traits'):
         provide_traits = composite_clazz.provide_traits
-        if a_trait in provide_traits:
-            provide_trait = provide_traits[a_trait]
-            attrname_map = dict(a_trait._trait_attrname_map)
-            attrname_map.update(provide_trait)
+        attrname_map = dict(a_trait._trait_attrname_map)
+        for req in provide_traits:
+            if req.trait_clazz == a_trait:
+                attrname_map[req] = provide_traits[req]
+                pass
             pass
         pass
     
@@ -89,13 +100,13 @@
     return derived
 
 
-## \brief Handle explicity providing for requires.
+## \brief Check explicity providing for requires.
 #
 # Composite maps require attributes of traits to the attribute, with
 # the same name, of composition class by default.  But, composition
 # class can specify name of the attribute that will satisfy a require.
 #
-def _handle_provide_traits(clazz):
+def _check_provide_traits(clazz):
     traits = clazz.use_traits
     
     #
@@ -106,20 +117,19 @@
             raise TypeError, \
                 'provide_traits of a composite must be a dictionary'
         
-        provide_set = set(clazz.provide_traits.keys())
+        provide_set = set([req.trait_clazz
+                           for req in clazz.provide_traits.keys()])
         trait_set = set(traits)
         unused_set = provide_set - trait_set
         if unused_set:
             raise ValueError, \
                 'can not find %s in provide_traits' % (repr(unused_set.pop()))
 
-        for trait, attrname_map in clazz.provide_traits.items():
-            for req in attrname_map:
-                if not isinstance(req, require):
-                    raise TypeError, \
-                        '%s is not a require: key of an ' \
-                        'attribute name map must be a require' % (repr(req))
-                pass
+        for req in clazz.provide_traits:
+            if not isinstance(req, require):
+                raise TypeError, \
+                    '%s is not a require: key of an ' \
+                    'attribute name map must be a require' % (repr(req))
             pass
         pass
     pass
@@ -161,11 +171,6 @@
         derived = derive_trait(a_trait, clazz)
         derived_traits[a_trait] = derived
 
-        if a_trait in method_map_traits:
-            method_map_trait = method_map_traits[a_trait]
-        else:
-            method_map_trait = {}
-        
         for attr in dir(derived):
             if attr not in attrname_cnts: # hidden
                 continue
@@ -176,7 +181,7 @@
                 continue
 
             value = getattr(a_trait, attr)
-            if value in method_map_trait: # do it later
+            if value in method_map_traits: # do it later
                 continue
             
             value = getattr(derived, attr)
@@ -192,23 +197,23 @@
         pass
 
     #
-    # Map methods specified in method_map_traits.
+    # Set a proxy for methods specified in method_map_traits.
     #
-    for a_trait, method_map_trait in method_map_traits.items():
+    for method, attrname in method_map_traits.items():
+        if not callable(method):
+            raise TypeError, \
+                '%s.%s is not a callable' % (repr(a_trait), repr(method))
+        
+        a_trait = method.im_class
         if a_trait not in derived_traits:
             raise TypeError, \
                 '%s is not a trait used by the composition class' % \
                 (repr(a_trait))
         
         derived = derived_traits[a_trait]
-        for method, attrname in method_map_trait.items():
-            if not callable(method):
-                raise TypeError, \
-                    '%s.%s is not a callable' % (repr(a_trait), repr(method))
-            func = method.im_func
-            proxy = trait_method_proxy(derived, func)
-            setattr(clazz, attrname, proxy)
-            pass
+        func = method.im_func
+        proxy = trait_method_proxy(derived, func)
+        setattr(clazz, attrname, proxy)
         pass
     pass
 
@@ -253,10 +258,9 @@
 # By default, traits map attribute 'var_a' to 'var_a' of instances of
 # composition classes.  But, you can change it by specifying the map
 # in an attribute, named 'provide_traits', defined in composition
-# class.  The attribute provide_traits is a dictionary mapping from
-# trait class to a dictionary, named 'attrname_map' for the trait.
-# The attrname_map maps require attributes of the trait to names of
-# attributes of instances of the composition class.
+# class.  The attribute provide_traits of a composition class is a
+# dictionary mapping from require attributes of used traits to names
+# of attributes of the composition class.
 #
 def composite(clazz):
     if not hasattr(clazz, 'use_traits'):
@@ -269,7 +273,7 @@
             raise TypeError, '%s is not a trait' % (repr(a_trait))
         pass
 
-    _handle_provide_traits(clazz)
+    _check_provide_traits(clazz)
     
     _include_methods(clazz)
     
@@ -296,12 +300,8 @@
     @composite
     class hello_bye(object):
         use_traits = (hello, bye)
-        
-        provide_hello = {hello.msg: 'msg1'}
-        provide_traits = {hello: provide_hello}
-        
-        method_map_hello = {hello.hello: 'hello1'}
-        method_map_traits = {hello: method_map_hello}
+        provide_traits = {hello.msg: 'msg1'}
+        method_map_traits = {hello.hello: 'hello1'}
 
         msg = 'hello_bye'
         msg1 = 'hello_bye_msg1'