[Commits] (vajda) - added onValueChanged() method to run after value changed on an item

commits at osafoundation.org commits at osafoundation.org
Thu Apr 28 20:50:38 PDT 2005


Commit by: vajda
Modified files:
chandler/repository/item/Access.py 1.4 1.5
chandler/repository/item/Item.py 1.207 1.208
chandler/repository/item/RefCollections.py 1.16 1.17
chandler/repository/item/Values.py 1.46 1.47
chandler/repository/packs/chandler/Parcel.kind 1.1 1.2
chandler/repository/packs/schema/model/schemaHash.attr None 1.1
chandler/repository/packs/schema/model/Attribute.kind 1.13 1.14
chandler/repository/packs/schema/model/Kind.kind 1.30 1.31
chandler/repository/persistence/DBContainer.py 1.39 1.40
chandler/repository/persistence/DBItemIO.py 1.9 1.10
chandler/repository/schema/Alias.py 1.12 1.13
chandler/repository/schema/Attribute.py 1.19 1.20
chandler/repository/schema/Cloud.py 1.28 1.29
chandler/repository/schema/Kind.py 1.109 1.110
chandler/repository/schema/TypeHandler.py 1.3 1.4
chandler/repository/schema/Types.py 1.80 1.81
chandler/repository/tests/TestImport.py 1.1 1.2
chandler/repository/tests/classes/Movie.py 1.3 1.4

Log message:
   - added onValueChanged() method to run after value changed on an item
   - saving Long values as 'long long', repository format changed to 0.5.1
   - added Item.hashItem(), specialized and cached result for schema items
   - added schema hash comparing when importing schema
   - kind mixin logic now uses schema hashes for naming mixin kinds and classes
   - mixin kinds' mixins attribute now contains list of constituent kind paths
   - for consistency onItemCopy() now takes (view, original) as arguments


ViewCVS links:
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/Access.py.diff?r1=text&tr1=1.4&r2=text&tr2=1.5
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/Item.py.diff?r1=text&tr1=1.207&r2=text&tr2=1.208
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/RefCollections.py.diff?r1=text&tr1=1.16&r2=text&tr2=1.17
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/Values.py.diff?r1=text&tr1=1.46&r2=text&tr2=1.47
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/chandler/Parcel.kind.diff?r1=text&tr1=1.1&r2=text&tr2=1.2
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema/model/schemaHash.attr?rev=1.1&content-type=text/vnd.viewcvs-markup
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema/model/Attribute.kind.diff?r1=text&tr1=1.13&r2=text&tr2=1.14
http://cvs.osafoundation.org/index.cgi/chandler/repository/packs/schema/model/Kind.kind.diff?r1=text&tr1=1.30&r2=text&tr2=1.31
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/DBContainer.py.diff?r1=text&tr1=1.39&r2=text&tr2=1.40
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/DBItemIO.py.diff?r1=text&tr1=1.9&r2=text&tr2=1.10
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/Alias.py.diff?r1=text&tr1=1.12&r2=text&tr2=1.13
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/Attribute.py.diff?r1=text&tr1=1.19&r2=text&tr2=1.20
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/Cloud.py.diff?r1=text&tr1=1.28&r2=text&tr2=1.29
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/Kind.py.diff?r1=text&tr1=1.109&r2=text&tr2=1.110
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/TypeHandler.py.diff?r1=text&tr1=1.3&r2=text&tr2=1.4
http://cvs.osafoundation.org/index.cgi/chandler/repository/schema/Types.py.diff?r1=text&tr1=1.80&r2=text&tr2=1.81
http://cvs.osafoundation.org/index.cgi/chandler/repository/tests/TestImport.py.diff?r1=text&tr1=1.1&r2=text&tr2=1.2
http://cvs.osafoundation.org/index.cgi/chandler/repository/tests/classes/Movie.py.diff?r1=text&tr1=1.3&r2=text&tr2=1.4

Index: chandler/repository/persistence/DBContainer.py
diff -u chandler/repository/persistence/DBContainer.py:1.39 chandler/repository/persistence/DBContainer.py:1.40
--- chandler/repository/persistence/DBContainer.py:1.39	Fri Mar 25 13:53:57 2005
+++ chandler/repository/persistence/DBContainer.py	Thu Apr 28 20:50:34 2005
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.39 $"
-__date__      = "$Date: 2005/03/25 21:53:57 $"
+__revision__  = "$Revision: 1.40 $"
+__date__      = "$Date: 2005/04/29 03:50:34 $"
 __copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -1062,7 +1062,10 @@
 
 class ValueContainer(DBContainer, CValueContainer):
 
-    FORMAT_VERSION = 0x00050000
+    # 0.5.0: first tracked format version
+    # 0.5.1: 'Long' values saved as long long (64 bit)
+
+    FORMAT_VERSION = 0x00050100
 
     def __init__(self, store, name, txn, **kwds):
 

Index: chandler/repository/schema/Types.py
diff -u chandler/repository/schema/Types.py:1.80 chandler/repository/schema/Types.py:1.81
--- chandler/repository/schema/Types.py:1.80	Mon Apr 18 12:41:36 2005
+++ chandler/repository/schema/Types.py	Thu Apr 28 20:50:34 2005
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.80 $"
-__date__      = "$Date: 2005/04/18 19:41:36 $"
+__revision__  = "$Revision: 1.81 $"
+__date__      = "$Date: 2005/04/29 03:50:34 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -12,7 +12,9 @@
 import repository.util.URL
 
 from new import classobj
+from struct import pack
 
+from chandlerdb.util.uuid import _hash, _combine
 from repository.item.Item import Item
 from repository.schema.TypeHandler import TypeHandler
 from repository.item.ItemHandler import ValueHandler
@@ -29,7 +31,7 @@
 
         TypeHandler.typeHandlers[view][None] = self
 
-    def onItemCopy(self, view):
+    def onItemCopy(self, view, orig):
 
         TypeHandler.typeHandlers[view][None] = self
 
@@ -98,6 +100,9 @@
     def onItemLoad(self, view):
         self._registerTypeHandler(self.getImplementationType(), view)
 
+    def onItemCopy(self, view, orig):
+        self._registerTypeHandler(self.getImplementationType(), view)
+
     def onItemImport(self, view):
         if view is not self.itsView:
             implementationType = self.getImplementationType()
@@ -106,7 +111,7 @@
 
     def getImplementationType(self):
         return self.getAttributeValue('implementationTypes',
-                                      _attrDict=self._values)['python']
+                                      self._values)['python']
 
     def handlerName(self):
         return None
@@ -123,6 +128,17 @@
     def eval(self, value):
         return value
 
+    def hashItem(self):
+        """
+        Compute a hash value from this type's schema.
+
+        The hash value is computed from the type's path.
+
+        @return: an integer
+        """
+
+        return _hash(str(self.itsPath))
+
     # override this to compare types of the same category, like
     # Integer, Long and Float or String and Symbol
     # in order of 'relevance' for findTypes
@@ -153,6 +169,9 @@
     def readValue(self, itemReader, offset, data, withSchema, view, name):
         raise NotImplementedError, "%s._readValue" %(type(self))
 
+    def hashValue(self, value):
+        return _hash(self.makeString(value))
+
     NoneString = "__NONE__"
 
 
@@ -163,6 +182,11 @@
         super(String, self).onItemLoad(view)
         self._registerTypeHandler(str, view)
 
+    def onItemCopy(self, view, orig):
+
+        super(String, self).onItemCopy(view, orig)
+        self._registerTypeHandler(str, view)
+
     def onItemImport(self, view):
 
         super(String, self).onItemImport(view)
@@ -209,6 +233,13 @@
         
         return itemReader.readString(offset, data)
 
+    def hashValue(self, value):
+        
+        if type(value) is unicode:
+            value = value.encode('utf-8')
+
+        return _hash(value)
+
 
 class Symbol(Type):
 
@@ -274,6 +305,9 @@
     def readValue(self, itemReader, offset, data, withSchema, view, name):
         return itemReader.readInteger(offset, data)
 
+    def hashValue(self, value):
+        return _hash(pack('>l', value))
+
 
 class Long(Type):
 
@@ -302,6 +336,9 @@
     def readValue(self, itemReader, offset, data, withSchema, view, name):
         return itemReader.readLong(offset, data)
 
+    def hashValue(self, value):
+        return _hash(pack('>q', value))
+
 
 class Float(Type):
 
@@ -326,6 +363,9 @@
     def readValue(self, itemReader, offset, data, withSchema, view, name):
         return itemReader.readFloat(offset, data)
 
+    def hashValue(self, value):
+        return _hash(pack('>d', value))
+
     
 class Complex(Type):
 
@@ -349,6 +389,11 @@
         offset, imag = itemReader.readFloat(offset, data)
 
         return offset, complex(real, imag)
+
+    def hashValue(self, value):
+
+        return _combine(_hash(pack('>d', value.real)),
+                        _hash(pack('>d', value.imag)))
         
 
 class Boolean(Type):
@@ -376,6 +421,13 @@
 
         return itemReader.readBoolean(offset, data)
 
+    def hashValue(self, value):
+
+        if value == True:
+            return _hash('True')
+        else:
+            return _hash('False')
+
 
 class UUID(Type):
 
@@ -431,6 +483,13 @@
         
         return offset+17, chandlerdb.util.uuid.UUID(data[offset+1:offset+17])
 
+    def hashValue(self, value):
+
+        if value is None:
+            return 0
+
+        return value._hash        
+
 
 class SingleRef(Type):
 
@@ -494,6 +553,13 @@
 
         return False
 
+    def hashValue(self, value):
+
+        if value is None:
+            return 0
+
+        return _combine(_hash(str(self.itsPath)), value._uuid._hash)
+
 
 class Path(Type):
 
@@ -554,6 +620,13 @@
         offset, string = itemReader.readString(offset+1, data)
         return offset, repository.util.Path.Path(string)
 
+    def hashValue(self, value):
+
+        if value is None:
+            return 0
+
+        return _combine(_hash(str(self.itsPath)), _hash(str(value)))
+
 
 class URL(Type):
 
@@ -599,6 +672,13 @@
         offset, string = itemReader.readString(offset+1, data)
         return offset, repository.util.URL.URL(string)
 
+    def hashValue(self, value):
+
+        if value is None:
+            return 0
+
+        return _combine(_hash(str(self.itsPath)), _hash(str(value)))
+
 
 class NoneType(Type):
 
@@ -628,6 +708,9 @@
             raise AssertionError, 'invalid byte for None'
         return offset+1, None
 
+    def hashValue(self, value):
+        return 0
+
 
 class Class(Type):
 
@@ -644,7 +727,7 @@
         return ClassLoader.loadClass(data)
 
     def makeString(self, value):
-        return "%s.%s" %(value.__module__, value.__name__)
+        return '.'.join((value.__module__, value.__name__))
 
     def writeValue(self, itemWriter, buffer, item, value, withSchema):
         itemWriter.writeString(buffer, self.makeString(value))
@@ -652,6 +735,9 @@
     def readValue(self, itemReader, offset, data, withSchema, view, name):
         offset, string = itemReader.readString(offset, data)
         return offset, ClassLoader.loadClass(string)
+
+    def hashValue(self, value):
+        return _combine(_hash(str(self.itsPath)), _hash(self.makeString(value)))
         
 
 class Enumeration(Type):
@@ -690,6 +776,9 @@
             offset, integer = itemReader.readInteger(offset, data)
             return offset, self.getAttributeValue('values', _attrDict=self._values)[integer]
 
+    def hashValue(self, value):
+        return _combine(_hash(str(self.itsPath)), _hash(self.makeString(value)))
+
 
 class Struct(Type):
 
@@ -750,6 +839,9 @@
         if attrs.has_key('typeid'):
             typeHandler = itemHandler.repository[chandlerdb.util.uuid.UUID(attrs['typeid'])]
             value = typeHandler.makeValue(itemHandler.data)
+        elif attrs.has_key('typepath'):
+            typeHandler = itemHandler.repository.findPath(attrs['typepath'])
+            value = typeHandler.makeValue(itemHandler.data)
         elif attrs.has_key('type'):
             value = itemHandler.makeValue(attrs['type'], itemHandler.data)
         else:
@@ -817,9 +909,7 @@
 
     def writeValue(self, itemWriter, buffer, item, value, withSchema):
 
-        fields = self.getAttributeValue('fields',
-                                        _attrDict=self._values,
-                                        default={})
+        fields = self.getAttributeValue('fields', self._values, default={})
 
         for fieldName, field in fields.iteritems():
             default = self.getDefaultValue(fieldName) 
@@ -836,10 +926,9 @@
 
     def readValue(self, itemReader, offset, data, withSchema, view, name):
 
-        fields = self.getAttributeValue('fields', _attrDict=self._values,
-                                        default=None)
-
+        fields = self.getAttributeValue('fields', self._values, default=None)
         value = self.getImplementationType()()
+
         while True:
             offset, fieldName = itemReader.readSymbol(offset, data)
             if fieldName != '':
@@ -851,6 +940,27 @@
             else:
                 return offset, value
 
+    def hashValue(self, value):
+
+        view = self.itsView
+        hash = _hash(str(self.itsPath))
+        fields = self.getAttributeValue('fields', self._values, default={})
+
+        for fieldName, field in fields.iteritems():
+            default = self.getDefaultValue(fieldName) 
+            fieldValue = self.getFieldValue(value, fieldName, default)
+            if fieldValue == default:
+                continue
+            
+            fieldType = field.get('type', None)
+            hash = _combine(hash, _hash(fieldName))
+            if fieldType is not None:
+                hash = _combine(hash, fieldType.hashValue(fieldValue))
+            else:
+                hash = _combine(hash, TypeHandler.hashValue(view, fieldValue))
+
+        return hash
+
 
 class MXType(Struct):
 
@@ -1028,6 +1138,15 @@
         itemHandler.tagCounts[-1] -= 1
         itemHandler.valueEnd(itemHandler, attrs, **kwds)
 
+    def hashValue(self, value):
+
+        view = self.itsView
+        hash = _hash(str(self.itsPath))
+        for v in value:
+            hash = _combine(hash, TypeHandler.hashValue(view, v))
+
+        return hash
+
 
 class Dictionary(Collection):
 
@@ -1094,7 +1213,17 @@
     def readValue(self, itemReader, offset, data, withSchema, view, name):
 
         return itemReader.readDict(offset, data, withSchema, None, view, name)
-    
+
+    def hashValue(self, value):
+        
+        view = self.itsView
+        hash = _hash(str(self.itsPath))
+        for k, v in value.iteritems():
+            hash = _combine(hash, TypeHandler.hashValue(view, k))
+            hash = _combine(hash, TypeHandler.hashValue(view, v))
+
+        return hash
+
 
 class List(Collection):
 
@@ -1289,3 +1418,8 @@
     def handlerName(self):
 
         return 'lob'
+
+    def hashValue(self, value):
+
+        # for now
+        return 0

Index: chandler/repository/tests/classes/Movie.py
diff -u chandler/repository/tests/classes/Movie.py:1.3 chandler/repository/tests/classes/Movie.py:1.4
--- chandler/repository/tests/classes/Movie.py:1.3	Mon Feb 28 12:28:12 2005
+++ chandler/repository/tests/classes/Movie.py	Thu Apr 28 20:50:36 2005
@@ -13,7 +13,7 @@
         else:
             return 0
 
-    def onItemCopy(self, original):
+    def onItemCopy(self, view, original):
 
         print 'copied', self.title, 'from', original.itsUUID
 

Index: chandler/repository/schema/Cloud.py
diff -u chandler/repository/schema/Cloud.py:1.28 chandler/repository/schema/Cloud.py:1.29
--- chandler/repository/schema/Cloud.py:1.28	Mon Apr 18 12:41:36 2005
+++ chandler/repository/schema/Cloud.py	Thu Apr 28 20:50:34 2005
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.28 $"
-__date__      = "$Date: 2005/04/18 19:41:36 $"
+__revision__  = "$Revision: 1.29 $"
+__date__      = "$Date: 2005/04/29 03:50:34 $"
 __copyright__ = "Copyright (c) 2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -228,6 +228,9 @@
 
             uuid = other._uuid
             if uuid in items or uuid in references:
+                if uuid in copies:
+                    return copies[uuid]
+                
                 match = other.findMatch(view, matches)
                 if match is not None:
                     return match

Index: chandler/repository/item/RefCollections.py
diff -u chandler/repository/item/RefCollections.py:1.16 chandler/repository/item/RefCollections.py:1.17
--- chandler/repository/item/RefCollections.py:1.16	Mon Apr 18 12:41:30 2005
+++ chandler/repository/item/RefCollections.py	Thu Apr 28 20:50:32 2005
@@ -1,11 +1,11 @@
 
-__revision__  = "$Revision: 1.16 $"
-__date__      = "$Date: 2005/04/18 19:41:30 $"
+__revision__  = "$Revision: 1.17 $"
+__date__      = "$Date: 2005/04/29 03:50:32 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
 
-from chandlerdb.util.uuid import UUID
+from chandlerdb.util.uuid import UUID, _hash, _combine
 from repository.util.Path import Path
 from repository.util.LinkedMap import LinkedMap
 from repository.item.Indexes import NumericIndex, AttributeIndex, CompareIndex
@@ -924,6 +924,17 @@
     def _clearDirties(self):
         pass
 
+    def _hashValues(self):
+
+        hash = 0
+        for key in self.iterkeys():
+            link = self._get(key)
+            hash = _combine(hash, key._hash)
+            if link._alias is not None:
+                hash = _combine(hash, _hash(link._alias))
+
+        return hash
+    
     SETDIRTY = 0x0002
     READONLY = 0x0004
 

Index: chandler/repository/persistence/DBItemIO.py
diff -u chandler/repository/persistence/DBItemIO.py:1.9 chandler/repository/persistence/DBItemIO.py:1.10
--- chandler/repository/persistence/DBItemIO.py:1.9	Fri Mar 25 13:53:57 2005
+++ chandler/repository/persistence/DBItemIO.py	Thu Apr 28 20:50:34 2005
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.9 $"
-__date__      = "$Date: 2005/03/25 21:53:57 $"
+__revision__  = "$Revision: 1.10 $"
+__date__      = "$Date: 2005/04/29 03:50:34 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -82,7 +82,7 @@
 
     def writeLong(self, buffer, value):
         
-        buffer.write(pack('>l', value))
+        buffer.write(pack('>q', value))
         
     def writeFloat(self, buffer, value):
 
@@ -407,7 +407,7 @@
         return offset+4, unpack('>i', data[offset:offset+4])[0]
 
     def readLong(self, offset, data):
-        return offset+4, unpack('>l', data[offset:offset+4])[0]
+        return offset+8, unpack('>q', data[offset:offset+8])[0]
         
     def readFloat(self, offset, data):
         return offset+8, unpack('>d', data[offset:offset+8])[0]

Index: chandler/repository/item/Values.py
diff -u chandler/repository/item/Values.py:1.46 chandler/repository/item/Values.py:1.47
--- chandler/repository/item/Values.py:1.46	Mon Apr 18 12:41:30 2005
+++ chandler/repository/item/Values.py	Thu Apr 28 20:50:32 2005
@@ -1,16 +1,17 @@
 
-__revision__  = "$Revision: 1.46 $"
-__date__      = "$Date: 2005/04/18 19:41:30 $"
+__revision__  = "$Revision: 1.47 $"
+__date__      = "$Date: 2005/04/29 03:50:32 $"
 __copyright__ = "Copyright (c) 2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
-from chandlerdb.util.uuid import UUID
+from chandlerdb.util.uuid import UUID, _hash, _combine
 from chandlerdb.item.ItemError import *
 from repository.util.Path import Path
 from repository.util.Lob import Lob
 from repository.item.PersistentCollections import PersistentCollection
 from repository.item.RefCollections import RefList
 from repository.util.SingleRef import SingleRef
+from repository.schema.TypeHandler import TypeHandler
 
 
 class Values(dict):
@@ -235,7 +236,7 @@
         
         item = self._item
         kind = item._kind
-        repository = item.itsView
+        view = item.itsView
 
         for key, value in self.iteritems():
             if kind is not None:
@@ -269,13 +270,53 @@
                     attrs['flags'] = str(flags)
 
                 try:
-                    ValueHandler.xmlValue(repository, key, value, 'attribute',
+                    ValueHandler.xmlValue(view, key, value, 'attribute',
                                           attrType, attrCard, attrId, attrs,
                                           generator, withSchema)
                 except Exception, e:
                     e.args = ("while saving attribute '%s' of item %s, %s" %(key, item.itsPath, e.args[0]),)
                     raise
 
+    def _hashValues(self):
+
+        item = self._item
+        kind = item._kind
+        view = item.itsView
+        hash = 0
+
+        names = self.keys()
+        names.sort()
+        
+        for name in names:
+            if kind is not None:
+                attribute = kind.getAttribute(name, False, item)
+            else:
+                attribute = None
+
+            if attribute is not None:
+                persist = attribute.getAspect('persist', default=True)
+            else:
+                persist = True
+
+            if persist:
+                persist = self._getFlags(name) & Values.TRANSIENT == 0
+
+            if persist:
+                hash = _combine(hash, _hash(name))
+                value = self[name]
+                
+                if attribute is not None:
+                    attrType = attribute.getAspect('type')
+                else:
+                    attrType = None
+
+                if attrType is not None:
+                    hash = _combine(hash, attrType.hashValue(value))
+                else:
+                    hash = _combine(hash, TypeHandler.hashValue(view, value))
+
+        return hash
+
     def _prepareMerge(self):
 
         if not hasattr(self, '_original'):
@@ -708,6 +749,33 @@
                         self._xmlRef(name, value, generator, withSchema,
                                      version, attrs)
 
+    def _hashValues(self):
+
+        item = self._item
+        kind = item._kind
+        view = item.itsView
+        hash = 0
+
+        names = self.keys()
+        names.sort()
+
+        for name in names:
+            attribute = kind.getAttribute(name, False, item)
+            if attribute.getAspect('persist', default=True):
+                hash = _combine(hash, _hash(name))
+                value = self[name]
+                
+                if value is None:
+                    hash = _combine(hash, 0)
+                elif value._isUUID():
+                    hash = _combine(hash, value._hash)
+                elif value._isItem():
+                    hash = _combine(hash, value._uuid._hash)
+                elif value._isRefList():
+                    hash = _combine(hash, value._hashValues())
+
+        return hash
+
     def _clearDirties(self):
 
         super(References, self)._clearDirties()

Index: chandler/repository/schema/Alias.py
diff -u chandler/repository/schema/Alias.py:1.12 chandler/repository/schema/Alias.py:1.13
--- chandler/repository/schema/Alias.py:1.12	Fri Mar 18 13:41:51 2005
+++ chandler/repository/schema/Alias.py	Thu Apr 28 20:50:34 2005
@@ -1,10 +1,11 @@
 
-__revision__  = "$Revision: 1.12 $"
-__date__      = "$Date: 2005/03/18 21:41:51 $"
+__revision__  = "$Revision: 1.13 $"
+__date__      = "$Date: 2005/04/29 03:50:34 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
 
+from chandlerdb.util.uuid import _hash, _combine
 from repository.schema.Types import Type
 from repository.schema.TypeHandler import TypeHandler
 
@@ -75,3 +76,19 @@
                 return
 
         raise TypeError, "value '%s' of type '%s' unrecognized by %s" %(value, type(value), self.itsPath)
+
+    def hashItem(self):
+        """
+        Compute a hash value from this aliase's schema.
+
+        The hash value is computed from the aliase's path and types.
+
+        @return: an integer
+        """
+
+        hash = _hash(str(self.itsPath))
+        if 'types' in self._references:
+            for t in self.types:
+                hash = _combine(hash, t.hashItem())
+
+        return hash

Index: chandler/repository/item/Access.py
diff -u chandler/repository/item/Access.py:1.4 chandler/repository/item/Access.py:1.5
--- chandler/repository/item/Access.py:1.4	Wed Sep 29 13:03:56 2004
+++ chandler/repository/item/Access.py	Thu Apr 28 20:50:32 2005
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.4 $"
-__date__      = "$Date: 2004/09/29 20:03:56 $"
+__revision__  = "$Revision: 1.5 $"
+__date__      = "$Date: 2005/04/29 03:50:32 $"
 __copyright__ = "Copyright (c) 2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -20,12 +20,12 @@
 
 class ACL(list):
 
-    def verify(self, principal, pid, perms):
+    def verify(self, principal, perms):
 
         grant = deny = 0
 
         for ace in self:
-            on, off = ace.verify(principal, pid, perms)
+            on, off = ace.verify(principal, perms)
             grant |= on
             deny |= off
 

Index: chandler/repository/packs/schema/model/Kind.kind
diff -u chandler/repository/packs/schema/model/Kind.kind:1.30 chandler/repository/packs/schema/model/Kind.kind:1.31
--- chandler/repository/packs/schema/model/Kind.kind:1.30	Mon Apr  4 15:13:20 2005
+++ chandler/repository/packs/schema/model/Kind.kind	Thu Apr 28 20:50:33 2005
@@ -10,6 +10,8 @@
     <ref name="attributes" otherName="kinds"
          cardinality="list" otherCard="list">
 
+      <ref alias="schemaHash" type="path">/Core/schemaHash</ref>
+
       <!-- 
          - plus local attributes below:
          -     notFoundAttributes, inheritedAttributes,
@@ -221,7 +223,7 @@
     </ref>
 
     <ref name="type" otherName="typeFor" 
-         type="path" otherCard="list">/Core/UUID</ref>
+         type="path" otherCard="list">/Core/Path</ref>
     <attribute name="cardinality">list</attribute>
   </item>
 </items>

Index: chandler/repository/schema/TypeHandler.py
diff -u chandler/repository/schema/TypeHandler.py:1.3 chandler/repository/schema/TypeHandler.py:1.4
--- chandler/repository/schema/TypeHandler.py:1.3	Mon Apr 18 12:41:36 2005
+++ chandler/repository/schema/TypeHandler.py	Thu Apr 28 20:50:34 2005
@@ -1,6 +1,6 @@
 
-__revision__  = "$Revision: 1.3 $"
-__date__      = "$Date: 2005/04/18 19:41:36 $"
+__revision__  = "$Revision: 1.4 $"
+__date__      = "$Date: 2005/04/29 03:50:34 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -12,13 +12,6 @@
 
 class TypeHandler(object):
 
-    def makeValue(cls, typeName, data):
-
-        try:
-            return cls.typeDispatch[typeName](data)
-        except KeyError:
-            raise ValueError, "Unknown type %s for data: %s" %(typeName, data)
-
     def typeHandler(cls, view, value):
 
         try:
@@ -28,7 +21,16 @@
         except KeyError:
             pass
 
-        typeKind = cls.typeHandlers[view][None]
+        from repository.item.Item import Item
+        if isinstance(value, Item):
+            return cls.typeHandlers[view][SingleRef][0]
+
+        try:
+            typeKind = cls.typeHandlers[view][None]
+        except KeyError:
+            print type(value), value
+            raise
+        
         types = typeKind.findTypes(value)
         if types:
             return types[0]
@@ -39,6 +41,17 @@
 
         return cls.typeHandler(view, value).makeString(value)
 
+    def makeValue(cls, typeName, data):
+
+        try:
+            return cls.typeDispatch[typeName](data)
+        except KeyError:
+            raise ValueError, "Unknown type %s for data: %s" %(typeName, data)
+
+    def hashValue(cls, view, value):
+
+        return cls.typeHandler(view, value).hashValue(value)
+
     def clear(cls, view):
 
         try:
@@ -50,6 +63,7 @@
     typeHandler = classmethod(typeHandler)
     makeString = classmethod(makeString)
     makeValue = classmethod(makeValue)
+    hashValue = classmethod(hashValue)
     clear = classmethod(clear)
 
     typeHandlers = {}

Index: chandler/repository/packs/chandler/Parcel.kind
diff -u chandler/repository/packs/chandler/Parcel.kind:1.1 chandler/repository/packs/chandler/Parcel.kind:1.2
--- chandler/repository/packs/chandler/Parcel.kind:1.1	Mon Oct 18 13:05:03 2004
+++ chandler/repository/packs/chandler/Parcel.kind	Thu Apr 28 20:50:33 2005
@@ -5,7 +5,6 @@
   <item>
     <name>Parcel</name>
     <kind type="path">//Schema/Core/Kind</kind>
-    <class module="repository.schema.Kind">Kind</class>
 
     <ref name="attributes">
 
@@ -29,7 +28,6 @@
   <item>
     <name>author</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -43,7 +41,6 @@
   <item>
     <name>publisher</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -57,7 +54,6 @@
   <item>
     <name>status</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -71,7 +67,6 @@
   <item>
     <name>summary</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -85,7 +80,6 @@
   <item>
     <name>icon</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -99,7 +93,6 @@
   <item>
     <name>version</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -113,7 +106,6 @@
   <item>
     <name>createdOn</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -127,7 +119,6 @@
   <item>
     <name>modifiedOn</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -141,7 +132,6 @@
   <item>
     <name>namespace</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -156,7 +146,6 @@
   <item>
     <name>namespaceMap</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -171,7 +160,6 @@
   <item>
     <name>file</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">
@@ -186,7 +174,6 @@
   <item>
     <name>originalValues</name>
     <kind type="path">//Schema/Core/Attribute</kind>
-    <class module="repository.schema.Attribute">Attribute</class>
     <parent type="path">//Schema/Core/Parcel</parent>
 
     <ref name="kinds">

Index: chandler/repository/schema/Kind.py
diff -u chandler/repository/schema/Kind.py:1.109 chandler/repository/schema/Kind.py:1.110
--- chandler/repository/schema/Kind.py:1.109	Mon Apr 18 12:41:36 2005
+++ chandler/repository/schema/Kind.py	Thu Apr 28 20:50:34 2005
@@ -1,12 +1,12 @@
 
-__revision__  = "$Revision: 1.109 $"
-__date__      = "$Date: 2005/04/18 19:41:36 $"
+__revision__  = "$Revision: 1.110 $"
+__date__      = "$Date: 2005/04/29 03:50:34 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
 from new import classobj
 
-from chandlerdb.util.uuid import UUID, _combine
+from chandlerdb.util.uuid import UUID, _hash, _combine
 from chandlerdb.schema.descriptor import CDescriptor
 from chandlerdb.item.ItemError import NoSuchAttributeError, SchemaError
 
@@ -17,6 +17,7 @@
 from repository.util.Path import Path
 from repository.util.SingleRef import SingleRef
 from repository.item.Monitors import Monitors, Monitor
+from repository.schema.TypeHandler import TypeHandler
 
 
 class Kind(Item):
@@ -96,7 +97,7 @@
         if sync is not None:
             if sync == 'attributes':
                 attributes = self.getAttributeValue('attributes',
-                                                    _attrDict=self._references,
+                                                    self._references,
                                                     default=[])
             elif sync == 'superKinds':
                 attributes = set(a._uuid for n, a, k in self.iterAttributes())
@@ -225,13 +226,10 @@
 
         superClasses = []
         
-        hash = _combine(0, self._uuid._hash)
-        for superKind in self.getAttributeValue('superKinds',
-                                                _attrDict=self._references):
+        for superKind in self.getAttributeValue('superKinds', self._references):
             c = superKind.getItemClass()
             if c is not Item and c not in superClasses:
                 superClasses.append(c)
-                hash = _combine(hash, superKind._uuid._hash)
 
         count = len(superClasses)
 
@@ -240,6 +238,10 @@
         elif count == 1:
             c = superClasses[0]
         else:
+            hash = 0
+            for c in superClasses:
+                hash = _combine(hash, _hash('.'.join((c.__module__,
+                                                      c.__name__))))
             if hash < 0:
                 hash = ~hash
             name = "class_%08x" %(hash)
@@ -255,8 +257,7 @@
 
         result = super(Kind, self).check(recursive)
         
-        if not self.getAttributeValue('superKinds', default=None,
-                                      _attrDict = self._references):
+        if not self.getAttributeValue('superKinds', self._references):
             if self is not self.getItemKind():
                 self.itsView.logger.warn('No superKinds for %s', self.itsPath)
                 result = False
@@ -382,7 +383,7 @@
 
         uuid = self.resolve(name)
         if uuid is not None:
-            if self.hasValue('attributes', uuid, _attrDict=self._references):
+            if self.hasValue('attributes', uuid, self._references):
                 return True
         elif self.inheritedAttributes.resolveAlias(name):
             return True
@@ -452,9 +453,8 @@
         if inherited:
             references = self._references
             inheritedAttributes = self.getAttributeValue('inheritedAttributes',
-                                                         _attrDict=references)
-            for superKind in self.getAttributeValue('superKinds',
-                                                    _attrDict=references):
+                                                         references)
+            for superKind in self.getAttributeValue('superKinds', references):
                 for name, attribute, k in superKind.iterAttributes():
                     if (attribute._uuid not in inheritedAttributes and
                         inheritedAttributes.resolveAlias(name) is None):
@@ -464,7 +464,7 @@
                 name = link._alias
                 if not self.resolve(name):
                     attribute = link.getValue(self)
-                    for kind in attribute.getAttributeValue('kinds', _attrDict=attribute._references):
+                    for kind in attribute.getAttributeValue('kinds', attribute._references):
                         if self.isKindOf(kind):
                             break
                     yield (name, attribute, kind)
@@ -475,8 +475,7 @@
             return None
 
         cache = True
-        for superKind in self.getAttributeValue('superKinds',
-                                                _attrDict=self._references):
+        for superKind in self.getAttributeValue('superKinds', self._references):
             if superKind is not None:
                 attribute = superKind.getAttribute(name, True)
                 if attribute is not None:
@@ -517,9 +516,9 @@
             else:
                 duplicates[superKind._uuid] = superKind
                 
-        hash = _combine(0, self._uuid._hash)
+        hash = self.hashItem()
         for superKind in superKinds:
-            hash = _combine(hash, superKind._uuid._hash)
+            hash = _combine(hash, superKind.hashItem())
         if hash < 0:
             hash = ~hash
         name = "mixin_%08x" %(hash)
@@ -531,8 +530,7 @@
 
             kind.addValue('superKinds', self)
             kind.superKinds.extend(superKinds)
-            kind.addValue('mixins', self._uuid)
-            kind.mixins.extend([sk._uuid for sk in superKinds])
+            kind.mixins = [sk.itsPath for sk in kind.superKinds]
             
         return kind
         
@@ -560,7 +558,7 @@
             kindOf = self._refList('kindOf', 'ofKind', False)
             self._references['kindOf'] = kindOf
             for superKind in self.getAttributeValue('superKinds',
-                                                    _attrDict=self._references):
+                                                    self._references):
                 kindOf.append(superKind)
                 kindOf.update(superKind._kindOf())
 
@@ -636,8 +634,7 @@
             self._values._clearTransient('classes')
             del self._values['classes']
 
-        for subKind in self.getAttributeValue('subKinds',
-                                              _attrDict=self._references,
+        for subKind in self.getAttributeValue('subKinds', self._references,
                                               default=[]):
             subKind.flushCaches(reason)
 
@@ -646,7 +643,9 @@
             for cls in Kind._kinds.get(self._uuid, []):
                 logger.warning('Change in %s caused syncing of attribute descriptors on class %s.%s for Kind %s', reason, cls.__module__, cls.__name__, self.itsPath)
                 self._setupDescriptors(cls, reason)
-            
+
+        if 'schemaHash' in self._values:
+            del self.schemaHash
 
     # begin typeness of Kind as SingleRef
     
@@ -697,6 +696,13 @@
         
         return offset+17, SingleRef(UUID(data[offset+1:offset+17]))
 
+    def hashValue(self, value):
+
+        if value is None:
+            return 0
+
+        return TypeHandler.hashValue(self.itsView, SingleRef(value.itsUUID))
+
     def handlerName(self):
 
         return 'ref'
@@ -734,12 +740,12 @@
         """
 
         results = []
-        clouds = self.getAttributeValue('clouds', default=None,
-                                        _attrDict=self._references)
+        clouds = self.getAttributeValue('clouds', self._references,
+                                        default=None)
 
         if clouds is None or clouds.resolveAlias(cloudAlias) is None:
             for superKind in self.getAttributeValue('superKinds',
-                                                    _attrDict=self._references):
+                                                    self._references):
                 results.extend(superKind.getClouds(cloudAlias))
 
         else:
@@ -747,6 +753,68 @@
 
         return results
 
+    def _hashItem(self):
+
+        hash = 0
+        isMixin = self.isMixin()
+
+        if not isMixin:
+            hash = _combine(hash, _hash(str(self.itsPath)))
+
+        for superKind in self.getAttributeValue('superKinds', self._references):
+            hash = _combine(hash, superKind.hashItem())
+
+        if not isMixin:
+            attributes = list(self.iterAttributes(False))
+            attributes.sort()
+            for name, attribute, kind in attributes:
+                hash = _combine(hash, _hash(name))
+                hash = _combine(hash, attribute.hashItem())
+
+        return hash
+
+    def hashItem(self):
+        """
+        Compute a hash value from this kind's schema.
+
+        The hash value is computed from the kind's path (unless it is a
+        mixin kind), superKind and locally defined name - attribute item
+        hashes.
+
+        @return: an integer
+        """
+
+        if 'schemaHash' in self._values:
+            return self.schemaHash
+
+        self.schemaHash = hash = self._hashItem()
+        return hash
+
+    def onValueChanged(self, name):
+
+        if name == 'attributeHash':
+            if 'schemaHash' in self._values:
+                del self.schemaHash
+
+    def findMatch(self, view, matches=None):
+
+        if matches is not None:
+            match = matches.get(self)
+        else:
+            match = None
+            
+        if match is None:
+            match = view.find(self._uuid)
+            if match is None:
+                match = view.find(self.itsPath)
+                if not (match is None or matches is None):
+                    if not (self is match or
+                            self.hashItem() == match.hashItem()):
+                        raise SchemaError, ("kind matches are incompatible: %s %s", self.itsPath, match.itsPath)
+                    matches[self] = match
+
+        return match
+
 
     NoneString = "__NONE__"
     _classes = {}

Index: chandler/repository/item/Item.py
diff -u chandler/repository/item/Item.py:1.207 chandler/repository/item/Item.py:1.208
--- chandler/repository/item/Item.py:1.207	Wed Apr 20 11:45:51 2005
+++ chandler/repository/item/Item.py	Thu Apr 28 20:50:32 2005
@@ -1,10 +1,10 @@
 
-__revision__  = "$Revision: 1.207 $"
-__date__      = "$Date: 2005/04/20 18:45:51 $"
+__revision__  = "$Revision: 1.208 $"
+__date__      = "$Date: 2005/04/29 03:50:32 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
-from chandlerdb.util.uuid import UUID
+from chandlerdb.util.uuid import UUID, _hash, _combine
 from chandlerdb.schema.descriptor import _countAccess
 from chandlerdb.item.item import CItem
 from chandlerdb.item.ItemError import *
@@ -570,6 +570,8 @@
             otherName = self._kind.getOtherName(name, _attrID, self)
             _attrDict._removeValue(name, value, otherName)
 
+        if hasattr(type(self), 'onValueChanged'):
+            self.onValueChanged(name)
         Item._monitorsClass.invoke('remove', self, name)
 
     def hasChild(self, name, load=True):
@@ -1193,6 +1195,8 @@
                 assert attrDict is not None
                 attrDict._setDirty(attribute)
                 if not noMonitors:
+                    if hasattr(type(self), 'onValueChanged'):
+                        self.onValueChanged(attribute)
                     Item._monitorsClass.invoke('set', self, attribute)
                 
             _countAccess(self)
@@ -1374,7 +1378,7 @@
         item.setDirty(Item.NDIRTY)
 
         if hasattr(cls, 'onItemCopy'):
-            item.onItemCopy(self)
+            item.onItemCopy(item.itsView, self)
 
         return item
 
@@ -2233,6 +2237,29 @@
 
         self._status &= ~Item.MERGED
 
+    def hashItem(self):
+        """
+        Compute a hash value from this item's class, kind and attribute values.
+
+        The hash value is computed from the item's class name, kind hash,
+        and persistent attribute name-value pairs. The version, uuid,
+        parent, children of the item are not used in the computation. The
+        returned hash value can be used to compare items for schema and
+        value sameness.
+
+        @return: an integer
+        """
+
+        cls = type(self)
+
+        hash = _hash('.'.join((cls.__module__, cls.__name__)))
+        if self._kind is not None:
+            hash = _combine(hash, self._kind.hashItem())
+        hash = _combine(hash, self._values._hashValues())
+        hash = _combine(hash, self._references._hashValues())
+
+        return hash
+
     def __new__(cls, *args, **kwds):
 
         item = CItem.__new__(cls, *args, **kwds)

Index: chandler/repository/packs/schema/model/Attribute.kind
diff -u chandler/repository/packs/schema/model/Attribute.kind:1.13 chandler/repository/packs/schema/model/Attribute.kind:1.14
--- chandler/repository/packs/schema/model/Attribute.kind:1.13	Mon Jun 28 11:21:02 2004
+++ chandler/repository/packs/schema/model/Attribute.kind	Thu Apr 28 20:50:33 2005
@@ -10,6 +10,8 @@
     <ref name="attributes" otherName="kinds" cardinality="list" 
          otherCard="list">
 
+      <ref alias="schemaHash" type="path">/Core/schemaHash</ref>
+
       <!-- 
          - plus local attributes below:
          -     required, persist, cardinality, type,

Index: chandler/repository/tests/TestImport.py
diff -u chandler/repository/tests/TestImport.py:1.1 chandler/repository/tests/TestImport.py:1.2
--- chandler/repository/tests/TestImport.py:1.1	Mon Apr 18 12:41:37 2005
+++ chandler/repository/tests/TestImport.py	Thu Apr 28 20:50:35 2005
@@ -2,8 +2,8 @@
 Test importing of items across views and nullRepositoryView
 """
 
-__revision__  = "$Revision: 1.1 $"
-__date__      = "$Date: 2005/04/18 19:41:37 $"
+__revision__  = "$Revision: 1.2 $"
+__date__      = "$Date: 2005/04/29 03:50:35 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -93,6 +93,7 @@
         view = self.rep.view
 
         nv.loadPack(self.schemaPack)
+        nv.loadPack(self.chandlerPack)
         nv.loadPack(cineguidePack)
         nv.findPath('//CineGuide/KHepburn').movies.addIndex('n', 'numeric')
         nv.findPath('//CineGuide/KHepburn').movies.addIndex('t', 'attribute',

Index: chandler/repository/schema/Attribute.py
diff -u chandler/repository/schema/Attribute.py:1.19 chandler/repository/schema/Attribute.py:1.20
--- chandler/repository/schema/Attribute.py:1.19	Fri Mar 18 13:41:51 2005
+++ chandler/repository/schema/Attribute.py	Thu Apr 28 20:50:34 2005
@@ -1,11 +1,14 @@
 
-__revision__  = "$Revision: 1.19 $"
-__date__      = "$Date: 2005/03/18 21:41:51 $"
+__revision__  = "$Revision: 1.20 $"
+__date__      = "$Date: 2005/04/29 03:50:34 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
+from chandlerdb.util.uuid import _hash, _combine
+from chandlerdb.item.ItemError import SchemaError
 from repository.item.Item import Item
 from repository.schema.Kind import Kind
+from repository.schema.TypeHandler import TypeHandler
 
 
 class Attribute(Item):
@@ -76,3 +79,79 @@
             return root.walk(path, callable, index, **kwds)
 
         return None
+
+    def _hashItem(self):
+
+        hash = 0
+        view = self.itsView
+
+        item = self.getAttributeValue('superAttribute', self._references,
+                                      default=None)
+        if item is not None:
+            hash = _combine(hash, item.hashItem())
+
+        for aspect in Attribute.valueAspects:
+            value = self.getAttributeValue(aspect, self._values, 
+                                           default=Item.Nil)
+                                           
+            if value is not Item.Nil:
+                hash = _combine(hash, _hash(aspect))
+                type = self.getAttributeAspect(aspect, 'type', default=None)
+                if type is not None:
+                    hash = _combine(hash, type.hashValue(value))
+                else:
+                    hash = _combine(hash, TypeHandler.hashValue(view, value))
+
+        item = self.getAttributeValue('type', self._references,
+                                      default=None)
+        if item is not None:
+            if isinstance(item, Kind):
+                hash = _combine(hash, _hash(str(item.itsPath)))
+            else:
+                hash = _combine(hash, item.hashItem())
+
+        return hash
+
+    def hashItem(self):
+
+        if 'schemaHash' in self._values:
+            return self.schemaHash
+
+        self.schemaHash = hash = self._hashItem()
+        return hash
+
+    def onValueChanged(self, name):
+
+        if ('schemaHash' in self._values and
+            (name in Attribute.valueAspects or
+             name in Attribute.refAspects)):
+            del self.schemaHash
+            if 'kinds' in self._references:
+                for kind in self.kinds:
+                    kind.onValueChanged('attributeHash')
+
+    def findMatch(self, view, matches=None):
+
+        if matches is not None:
+            match = matches.get(self)
+        else:
+            match = None
+            
+        if match is None:
+            match = view.find(self._uuid)
+            if match is None:
+                match = view.find(self.itsPath)
+                if not (match is None or matches is None):
+                    if not (self is match or
+                            self.hashItem() == match.hashItem()):
+                        raise SchemaError, ("Attribute matches are incompatible: %s %s", self.itsPath, match.itsPath)
+                    matches[self] = match
+
+        return match
+
+    valueAspects = ('required', 'persist', 'cardinality',
+                    'defaultValue', 'initialValue',
+                    'inheritFrom', 'redirectTo', 'otherName', 'companion',
+                    'deletePolicy', 'copyPolicy', 'countPolicy')
+
+    refAspects = ('type', 'superAttribute')



More information about the Commits mailing list