def readItem(self, view, afterLoadHooks): status = self.status withSchema = (status & Item.CORESCHEMA) != 0 isContainer = (status & Item.CONTAINER) != 0 status &= Item.CORESCHEMA kind = self._kind(self.uKind, withSchema, view, afterLoadHooks) parent = self._parent(self.uParent, withSchema, view, afterLoadHooks) cls = self._class(self.moduleName, self.className, withSchema, kind, view, afterLoadHooks) values = Values(None) references = References(None) self._values(values, references, self.uValues, kind, withSchema, view, afterLoadHooks) instance = view._reuseItemInstance(self.uItem) if instance is not None: if cls is not type(instance): instance.__class__ = cls item = self.item = instance status |= item._status & item.PINNED else: item = self.item = cls.__new__(cls) item._fillItem(self.name, parent, kind, uuid=self.uItem, values=values, references=references, afterLoadHooks=afterLoadHooks, version=self.version, status=status, update=False) if isContainer: item._children = view._createChildren(item, False) values._setItem(item) references._setItem(item) for name, value in values.iteritems(): if isinstance(value, ItemValue): value._setOwner(item, name) if kind is not None: afterLoadHooks.append(lambda view: kind._setupClass(cls)) if hasattr(cls, 'onItemLoad'): afterLoadHooks.append(item.onItemLoad) return item
def instantiateItem(self, name, parent, uuid, cls=None, version=0, withInitialValues=False): """ Instantiate an existing item of this kind. This method is intended to help in instantiating an existing item, that is an item in this or another repository for which there already exists a UUID. The item's constructor is not invoked, the item's onItemLoad method is invoked if defined. @param name: The name of the item. It must be unique among the names this item's siblings. C{name} may be C{None}. @type name: a string or C{None} to create an anonymous item. @param parent: The parent of this item. All items require a parent unless they are a repository root in which case C{parent} is a repository view. @type parent: an item or the item's repository view @param uuid: The uuid for the item. @type uuid: L{UUID<chandlerdb.util.uuid.UUID>} @param cls: an optional python class to instantiate the item with, defaults to the class set on this kind. @type cls: a python new style class, that is, a type instance @param version: the optional version of this item instance, zero by default. @type version: integer @param withInitialValues: optionally set the initial values for attributes as specified in this Kind's attribute definitions. @type withInitialValues: boolean """ if cls is None: cls = self.getItemClass() values = Values(None) references = References(None) item = cls.__new__(cls) item._fillItem(name, parent, self, uuid=uuid, version=version, values=values, references=references) values._setItem(item) references._setItem(item) self._setupClass(cls) if withInitialValues: self.getInitialValues(item, values, references) if hasattr(cls, 'onItemLoad'): item.onItemLoad(self.itsView) return item
class ItemHandler(ValueHandler): """ A SAX ContentHandler implementation responsible for loading items. """ def __init__(self, repository, parent, afterLoadHooks, new): super(ItemHandler, self).__init__(repository) self.loading = repository.isLoading() self.parent = parent self.afterLoadHooks = afterLoadHooks self.item = None self.new = new self.values = None self.references = None def refStart(self, itemHandler, attrs): if self.tags[-1] == 'item': name = attrs['name'] attribute = self.getAttribute(name) self.attributes.append(attribute) flags = attrs.get('flags', None) if flags is not None: flags = int(flags) self.references._setFlags(name, flags) readOnly = flags & Values.READONLY else: readOnly = False cardinality = self.getCardinality(attribute, attrs) if cardinality != 'single': if cardinality == 'dict': self.repository.logger.warning("Warning, 'dict' cardinality for reference attribute %s on %s is deprecated, use 'list' instead", name, self.name or self.uuid) self._setupRefList(name, attribute, readOnly, attrs) def _setupRefList(self, name, attribute, readOnly, attrs): refList = None otherName = self.getOtherName(name, attribute, attrs) if 'uuid' in attrs: uuid = UUID(attrs['uuid']) else: uuid = None if self.update and attrs.get('operation') == 'append': refList = self.item._references.get(name) if refList is None: refList = self.repository._createRefList(None, name, otherName, True, readOnly, self.new, uuid) self.collections.append(refList) def itemStart(self, itemHandler, attrs): super(ItemHandler, self).itemStart(itemHandler, attrs) if self.values is None: self.values = Values(None) if self.references is None: self.references = References(None) self.refs = [] self.name = None self.cls = None self.parentRef = None self.isContainer = False self.uuid = UUID(attrs.get('uuid')) self.version = int(attrs.get('version', '0')) self.update = update = attrs.get('update') self.delete = delete = attrs.get('delete') def _find(spec): typeAttr = attrs.get('type', 'path') if typeAttr == 'path': item = self.parent.find(Path(spec)) elif typeAttr == 'uuid': item = self.parent.find(UUID(spec)) else: raise TypeError, typeAttr if item is None: raise NoSuchItemError, (spec, self.version) return item if update is not None: item = _find(update) elif delete is not None: item = _find(delete) else: item = None if item is not None: self.item = item self.cls = type(item) self.version = item._version self.name = item.itsName self.kind = item.itsKind self.uuid = item.itsUUID self.parent = item.itsParent def itemEnd(self, itemHandler, attrs): from repository.item.Item import Item if self.withSchema: status = Item.CORESCHEMA else: status = 0 cls = self.cls if cls is None: if self.kind is None: cls = Item else: cls = self.kind.getItemClass() instance = self.repository._reuseItemInstance(self.uuid) if instance is not None: if cls is not type(instance): raise TypeError, 'Class for item has changed from %s to %s' %(type(instance), cls) item = self.item = instance status |= item._status & item.PINNED instance = None elif self.update or self.delete: item = self.item values = item._values references = item._references for name, value in self.values.iteritems(): values[name] = value item.setDirty(Item.VDIRTY, name, values, noMonitors=True) self.values = values for name, value in self.references.iteritems(): if not isinstance(value, dict): dirty = Item.VDIRTY item.setAttributeValue(name, value, references, None, False) else: dirty = Item.RDIRTY references[name] = value item.setDirty(dirty, name, references, noMonitors=True) self.references = references status = item._status | Item.NDIRTY else: item = self.item = cls.__new__(cls) item._fillItem(self.name, self.parent, self.kind, uuid = self.uuid, values = self.values, references = self.references, afterLoadHooks = self.afterLoadHooks, version = self.version, status = status, update = self.update) if self.isContainer and item._children is None: item._children = self.repository._createChildren(item, self.new) if not (self.update or self.delete): self.repository._registerItem(item) self.values._setItem(item) self.references._setItem(item) for attribute, value in self.values.iteritems(): if isinstance(value, ItemValue): value._setOwner(item, attribute) for refArgs in self.refs: other = refArgs._setItem(item) if self.loading: refArgs._setRef() elif other is None: self.afterLoadHooks.append(refArgs._setValue) else: refArgs._setValue(self.repository) self.afterLoadHooks.append(self.setupClass) if hasattr(cls, 'onItemLoad'): self.afterLoadHooks.append(item.onItemLoad) if self.delete: self.afterLoadHooks.append(item.delete) def setupClass(self, view): if self.update and isinstance(self.item, Kind): self.item.flushCaches('attributes', True) elif self.kind is not None: self.kind._setupClass(type(self.item)) def kindEnd(self, itemHandler, attrs): assert not self.item super(ItemHandler, self).kindEnd(itemHandler, attrs) if self.kind is None: if self.withSchema: self.afterLoadHooks.append(self._setKind) else: raise ValueError, "While loading %s, kind %s not found" %(self.name or self.uuid, self.kindRef) def _setKind(self, view): if self.item._kind is None: self.kind = view.find(self.kindRef) if self.kind is None: raise ValueError, 'Kind %s not found' %(self.kindRef) else: self.item._kind = self.kind def parentEnd(self, itemHandler, attrs): if attrs['type'] == 'uuid': self.parentRef = UUID(self.data) else: self.parentRef = Path(self.data) self.isContainer = attrs.get('container', 'False') == 'True' self.parent = self.repository.find(self.parentRef) if self.parent is None: self.afterLoadHooks.append(self._move) def _move(self, view): if self.item._parent is None: self.parent = view.find(self.parentRef) if self.parent is None: raise ValueError, 'Parent %s not found' %(self.parentRef) else: self.item.move(self.parent) def classEnd(self, itemHandler, attrs): self.cls = ClassLoader.loadClass(self.data, attrs['module']) def nameEnd(self, itemHandler, attrs): self.name = self.data def refEnd(self, itemHandler, attrs): if self.tags[-1] == 'item': attribute = self.attributes.pop() cardinality = self.getCardinality(attribute, attrs) otherCard = attrs.get('otherCard', None) else: cardinality = 'single' otherCard = self.tagAttrs[-1].get('otherCard', None) if cardinality == 'single': # cardinality of tag typeName = attrs.get('type', 'path') if typeName == 'path': ref = Path(self.data) elif typeName == 'none': self.references[attrs['name']] = None return else: ref = UUID(self.data) if self.collections: refList = self.collections[-1] self.refs.append(RefArgs(refList._name, None, refList._otherName, ref, otherCard=otherCard, otherAlias=attrs.get('otherAlias'), previous=self.refName(attrs, 'previous'), next=self.refName(attrs, 'next'), alias=attrs.get('alias'))) else: name = attrs['name'] otherName = self.getOtherName(name, self.getAttribute(name), attrs) self.refs.append(RefArgs(name, None, otherName, ref, otherCard=otherCard, otherAlias=attrs.get('otherAlias'))) else: value = self.collections.pop() self.references[attrs['name']] = value if value._indexes: self.afterLoadHooks.append(value._restoreIndexes) def indexEnd(self, itemHandler, attrs): if not self.collections: raise ValueError, self.tagAttrs[-1]['name'] refList = self.collections[-1] kwds = attrs.copy() del kwds['type'] del kwds['name'] refList.addIndex(attrs['name'], attrs['type'], **kwds) def refName(self, attrs, attr): try: return self.makeValue(attrs.get(attr + 'Type', 'str'), attrs[attr]) except KeyError: return None def getOtherName(self, name, attribute, attrs): otherName = attrs.get('otherName') if otherName is None and attribute is not None: otherName = self.kind.getOtherName(name, None, None, None) if otherName is None: raise TypeError, 'Undefined other endpoint for %s.%s of kind %s' %(self.name or self.uuid, name, self.kind.itsPath) return otherName
class ItemHandler(ValueHandler): """ A SAX ContentHandler implementation responsible for loading items. """ def __init__(self, repository, parent, afterLoadHooks, new): super(ItemHandler, self).__init__(repository) self.loading = repository.isLoading() self.parent = parent self.afterLoadHooks = afterLoadHooks self.item = None self.new = new self.values = None self.references = None def refStart(self, itemHandler, attrs): if self.tags[-1] == 'item': name = attrs['name'] attribute = self.getAttribute(name) self.attributes.append(attribute) flags = attrs.get('flags', None) if flags is not None: flags = int(flags) self.references._setFlags(name, flags) readOnly = flags & Values.READONLY else: readOnly = False cardinality = self.getCardinality(attribute, attrs) if cardinality != 'single': if cardinality == 'dict': self.repository.logger.warning( "Warning, 'dict' cardinality for reference attribute %s on %s is deprecated, use 'list' instead", name, self.name or self.uuid) self._setupRefList(name, attribute, readOnly, attrs) def _setupRefList(self, name, attribute, readOnly, attrs): refList = None otherName = self.getOtherName(name, attribute, attrs) if 'uuid' in attrs: uuid = UUID(attrs['uuid']) else: uuid = None if self.update and attrs.get('operation') == 'append': refList = self.item._references.get(name) if refList is None: refList = self.repository._createRefList(None, name, otherName, True, readOnly, self.new, uuid) self.collections.append(refList) def itemStart(self, itemHandler, attrs): super(ItemHandler, self).itemStart(itemHandler, attrs) if self.values is None: self.values = Values(None) if self.references is None: self.references = References(None) self.refs = [] self.name = None self.cls = None self.parentRef = None self.isContainer = False self.uuid = UUID(attrs.get('uuid')) self.version = int(attrs.get('version', '0')) self.update = update = attrs.get('update') self.delete = delete = attrs.get('delete') def _find(spec): typeAttr = attrs.get('type', 'path') if typeAttr == 'path': item = self.parent.find(Path(spec)) elif typeAttr == 'uuid': item = self.parent.find(UUID(spec)) else: raise TypeError, typeAttr if item is None: raise NoSuchItemError, (spec, self.version) return item if update is not None: item = _find(update) elif delete is not None: item = _find(delete) else: item = None if item is not None: self.item = item self.cls = type(item) self.version = item._version self.name = item.itsName self.kind = item.itsKind self.uuid = item.itsUUID self.parent = item.itsParent def itemEnd(self, itemHandler, attrs): from repository.item.Item import Item if self.withSchema: status = Item.CORESCHEMA else: status = 0 cls = self.cls if cls is None: if self.kind is None: cls = Item else: cls = self.kind.getItemClass() instance = self.repository._reuseItemInstance(self.uuid) if instance is not None: if cls is not type(instance): raise TypeError, 'Class for item has changed from %s to %s' % ( type(instance), cls) item = self.item = instance status |= item._status & item.PINNED instance = None elif self.update or self.delete: item = self.item values = item._values references = item._references for name, value in self.values.iteritems(): values[name] = value item.setDirty(Item.VDIRTY, name, values, noMonitors=True) self.values = values for name, value in self.references.iteritems(): if not isinstance(value, dict): dirty = Item.VDIRTY item.setAttributeValue(name, value, references, None, False) else: dirty = Item.RDIRTY references[name] = value item.setDirty(dirty, name, references, noMonitors=True) self.references = references status = item._status | Item.NDIRTY else: item = self.item = cls.__new__(cls) item._fillItem(self.name, self.parent, self.kind, uuid=self.uuid, values=self.values, references=self.references, afterLoadHooks=self.afterLoadHooks, version=self.version, status=status, update=self.update) if self.isContainer and item._children is None: item._children = self.repository._createChildren(item, self.new) if not (self.update or self.delete): self.repository._registerItem(item) self.values._setItem(item) self.references._setItem(item) for attribute, value in self.values.iteritems(): if isinstance(value, ItemValue): value._setOwner(item, attribute) for refArgs in self.refs: other = refArgs._setItem(item) if self.loading: refArgs._setRef() elif other is None: self.afterLoadHooks.append(refArgs._setValue) else: refArgs._setValue(self.repository) self.afterLoadHooks.append(self.setupClass) if hasattr(cls, 'onItemLoad'): self.afterLoadHooks.append(item.onItemLoad) if self.delete: self.afterLoadHooks.append(item.delete) def setupClass(self, view): if self.update and isinstance(self.item, Kind): self.item.flushCaches('attributes', True) elif self.kind is not None: self.kind._setupClass(type(self.item)) def kindEnd(self, itemHandler, attrs): assert not self.item super(ItemHandler, self).kindEnd(itemHandler, attrs) if self.kind is None: if self.withSchema: self.afterLoadHooks.append(self._setKind) else: raise ValueError, "While loading %s, kind %s not found" % ( self.name or self.uuid, self.kindRef) def _setKind(self, view): if self.item._kind is None: self.kind = view.find(self.kindRef) if self.kind is None: raise ValueError, 'Kind %s not found' % (self.kindRef) else: self.item._kind = self.kind def parentEnd(self, itemHandler, attrs): if attrs['type'] == 'uuid': self.parentRef = UUID(self.data) else: self.parentRef = Path(self.data) self.isContainer = attrs.get('container', 'False') == 'True' self.parent = self.repository.find(self.parentRef) if self.parent is None: self.afterLoadHooks.append(self._move) def _move(self, view): if self.item._parent is None: self.parent = view.find(self.parentRef) if self.parent is None: raise ValueError, 'Parent %s not found' % (self.parentRef) else: self.item.move(self.parent) def classEnd(self, itemHandler, attrs): self.cls = ClassLoader.loadClass(self.data, attrs['module']) def nameEnd(self, itemHandler, attrs): self.name = self.data def refEnd(self, itemHandler, attrs): if self.tags[-1] == 'item': attribute = self.attributes.pop() cardinality = self.getCardinality(attribute, attrs) otherCard = attrs.get('otherCard', None) else: cardinality = 'single' otherCard = self.tagAttrs[-1].get('otherCard', None) if cardinality == 'single': # cardinality of tag typeName = attrs.get('type', 'path') if typeName == 'path': ref = Path(self.data) elif typeName == 'none': self.references[attrs['name']] = None return else: ref = UUID(self.data) if self.collections: refList = self.collections[-1] self.refs.append( RefArgs(refList._name, None, refList._otherName, ref, otherCard=otherCard, otherAlias=attrs.get('otherAlias'), previous=self.refName(attrs, 'previous'), next=self.refName(attrs, 'next'), alias=attrs.get('alias'))) else: name = attrs['name'] otherName = self.getOtherName(name, self.getAttribute(name), attrs) self.refs.append( RefArgs(name, None, otherName, ref, otherCard=otherCard, otherAlias=attrs.get('otherAlias'))) else: value = self.collections.pop() self.references[attrs['name']] = value if value._indexes: self.afterLoadHooks.append(value._restoreIndexes) def indexEnd(self, itemHandler, attrs): if not self.collections: raise ValueError, self.tagAttrs[-1]['name'] refList = self.collections[-1] kwds = attrs.copy() del kwds['type'] del kwds['name'] refList.addIndex(attrs['name'], attrs['type'], **kwds) def refName(self, attrs, attr): try: return self.makeValue(attrs.get(attr + 'Type', 'str'), attrs[attr]) except KeyError: return None def getOtherName(self, name, attribute, attrs): otherName = attrs.get('otherName') if otherName is None and attribute is not None: otherName = self.kind.getOtherName(name, None, None, None) if otherName is None: raise TypeError, 'Undefined other endpoint for %s.%s of kind %s' % ( self.name or self.uuid, name, self.kind.itsPath) return otherName