[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