def test_import_field_ref(self): xml = """\ <registry> <record name="test.registry.field.override"> <field ref="test.registry.field" /> <value>Another value</value> </record> </registry> """ context = DummyImportContext(self.site, purge=False) context._files = {'registry.xml': xml} self.registry.records['test.registry.field'] = Record( field.TextLine(title=u"Simple record", default=u"N/A"), value=u"Sample value") importRegistry(context) self.assertEqual(2, len(self.registry.records)) self.assertTrue( IFieldRef.providedBy( self.registry.records['test.registry.field.override'].field) ) self.assertEqual( u"Simple record", self.registry.records['test.registry.field.override'].field.title ) self.assertEqual( u"value", self.registry.records['test.registry.field.override'].field.__name__ # noqa ) self.assertEqual( u"Another value", self.registry['test.registry.field.override'] )
def exportRecord(self, record): node = etree.Element('record') node.attrib['name'] = record.__name__ if IInterfaceAwareRecord.providedBy(record): node.attrib['interface'] = record.interfaceName node.attrib['field'] = record.fieldName # write field field = record.field if IFieldRef.providedBy(field): field_element = etree.Element('field') field_element.attrib['ref'] = field.recordName node.append(field_element) else: field_type = IFieldNameExtractor(record.field)() handler = queryUtility(IFieldExportImportHandler, name=field_type) if handler is None: self.logger.warning("Field type %s specified for record %s \ cannot be exported" % (field_type, record.__name__)) else: field_element = handler.write(record.field, None, field_type, elementName='field') node.append(field_element) # write value value_element = valueToElement(record.field, record.value, name='value', force=True) node.append(value_element) return node
def test_fieldref_interfaces(self): from plone.registry import field, FieldRef from plone.registry.interfaces import IFieldRef from zope.schema.interfaces import ICollection listField = field.List(value_type=field.ASCIILine()) ref = FieldRef('some.record', listField) self.assertTrue(ICollection.providedBy(ref)) self.assertTrue(IFieldRef.providedBy(ref))
def _setField(self, name, field): if not IPersistentField.providedBy(field): raise ValueError("The record's field must be an IPersistentField.") if IFieldRef.providedBy(field): if field.recordName not in self._fields: raise ValueError("Field reference points to non-existent record") self._fields[name] = field.recordName # a pointer, of sorts else: field.__name__ = 'value' self._fields[name] = field
def exportRecord(self, record): node = etree.Element('record') node.attrib['name'] = record.__name__ if IInterfaceAwareRecord.providedBy(record): node.attrib['interface'] = record.interfaceName node.attrib['field'] = record.fieldName # write field field = record.field if IFieldRef.providedBy(field): field_element = etree.Element('field') field_element.attrib['ref'] = field.recordName node.append(field_element) else: field_type = IFieldNameExtractor(record.field)() handler = queryUtility(IFieldExportImportHandler, name=field_type) if handler is None: self.logger.warning( 'Field type {0} specified for record {1} ' 'cannot be exported'.format(field_type, record.__name__) ) else: field_element = handler.write( record.field, None, field_type, elementName='field' ) node.append(field_element) # write value value_element = valueToElement( record.field, record.value, name='value', force=True ) node.append(value_element) return node
def importRecord(self, node): name = node.get('name', '') if node.get('delete') is not None: self.logger.warning( u"The 'delete' attribute of <record /> nodes is deprecated, " u"it should be replaced with 'remove'." ) remove = node.get('remove', node.get('delete', 'false')) interfaceName = node.get('interface', None) fieldName = node.get('field', None) if not name and (interfaceName and fieldName): prefix = node.get('prefix', None) if prefix is None: prefix = interfaceName name = "%s.%s" % (prefix, fieldName) if not name: raise NameError("No name given for <record /> node!") # Unicode is not supported name = str(name) __traceback_info__ = 'record name: {0}'.format(name) # Handle deletion and quit if remove.lower() == 'true': if name in self.context.records: del self.context.records[name] self.logger.info("Removed record %s." % name) else: self.logger.warning( "Record {0} was marked for deletion, but was not " "found.".format(name) ) return # See if we have an existing record existing_record = self.context.records.get(name, None) interface = None field = None value = _marker value_purge = True # If we are given an interface and field name, try to resolve them if interfaceName and fieldName: try: interface = resolve(interfaceName) field = IPersistentField(interface[fieldName]) except ImportError: self.logger.warning( 'Failed to import interface {0} for ' 'record {1}'.format(interfaceName, name) ) interface = None field = None except KeyError: self.logger.warning( 'Interface {0} specified for record %s has ' 'no field {1}.'.format(interfaceName, name, fieldName) ) interface = None field = None except TypeError: self.logger.warning( "Field {0} in interface {1} specified for record {2} " "cannot be used as a persistent field.".format( fieldName, interfaceName, name ) ) interface = None field = None # Find field and value nodes field_node = None value_node = None for child in node: if not isinstance(child.tag, str): continue elif child.tag.lower() == 'field': field_node = child elif child.tag.lower() == 'value': value_node = child # Let field not potentially override interface[fieldName] if field_node is not None: field_ref = field_node.attrib.get('ref', None) if field_ref is not None: # We have a field reference if field_ref not in self.context: raise KeyError( u'Record {0} references field for record {1}, ' u'which does not exist'.format(name, field_ref) ) ref_record = self.context.records[field_ref] field = FieldRef(field_ref, ref_record.field) else: # We have a standard field field_type = field_node.attrib.get('type', None) field_type_handler = queryUtility( IFieldExportImportHandler, name=field_type ) if field_type_handler is None: raise TypeError( "Field of type {0} used for record {1} is not " "supported.".format(field_type, name) ) else: field = field_type_handler.read(field_node) if not IPersistentField.providedBy(field): raise TypeError( "Only persistent fields may be imported. {0} used " "for record {1} is invalid.".format( field_type, name ) ) if field is not None and not IFieldRef.providedBy(field): # Set interface name and fieldName, if applicable field.interfaceName = interfaceName field.fieldName = fieldName # Fall back to existing record if neither a field node nor the # interface yielded a field change_field = True if field is None and existing_record is not None: change_field = False field = existing_record.field if field is None: raise ValueError( "Cannot find a field for the record {0}. Add a <field /> " "element or reference an interface and field name.".format( name ) ) # Extract the value if value_node is not None: value_purge = value_node.attrib.get('purge', '').lower() != 'false' value = elementToValue(field, value_node, default=_marker) # Now either construct or update the record if value is _marker: value = field.default value_purge = True if existing_record is not None: if change_field: existing_record.field = field existing_value = existing_record.value if change_field or value != existing_value: if not value_purge and type(value) == type(existing_value): if isinstance(value, list): value = ( existing_value + [v for v in value if v not in existing_value] ) elif isinstance(value, tuple): value = ( existing_value + tuple( [v for v in value if v not in existing_value] ) ) elif isinstance(value, (set, frozenset, )): value = existing_value.union(value) elif isinstance(value, dict): for key, value in value.items(): # check if value is list, if so, let's add # instead of overridding if ( type(value) == list and key in existing_value and not shouldPurgeList(value_node, key) ): existing = existing_value[key] for item in existing: # here, we'll remove existing items # point is that we don't want # duplicates and don't want to reorder if item in value: value.remove(item) existing.extend(value) value = existing existing_value[key] = value value = existing_value existing_record.value = value else: self.context.records[name] = Record(field, value)
def importRecord(self, node): name = node.get('name', '') if node.get('delete') is not None: self.logger.warning(u"The 'delete' attribute of <record /> nodes " u"is deprecated, it should be replaced with " u"'remove'.") remove = node.get('remove', node.get('delete', 'false')) interfaceName = node.get('interface', None) fieldName = node.get('field', None) if not name and (interfaceName and fieldName): prefix = node.get('prefix', None) if prefix is None: prefix = interfaceName name = "%s.%s" % (prefix, fieldName) if not name: raise NameError("No name given for <record /> node!") # Unicode is not supported name = str(name) # Handle deletion and quit if remove.lower() == 'true': if name in self.context.records: del self.context.records[name] self.logger.info("Removed record %s." % name) else: self.logger.warning( "Record %s was marked for deletion, but was not found." % name) return # See if we have an existing record existing_record = self.context.records.get(name, None) interface = None field = None value = _marker value_purge = True # If we are given an interface and field name, try to resolve them if interfaceName and fieldName: try: interface = resolve(interfaceName) field = IPersistentField(interface[fieldName]) except ImportError: self.logger.warning("Failed to import interface %s for \ record %s" % (interfaceName, name)) interface = None field = None except KeyError: self.logger.warning("Interface %s specified for record %s has \ no field %s." % (interfaceName, name, fieldName)) interface = None field = None except TypeError: self.logger.warning("Field %s in interface %s specified for \ record %s cannot be used as a persistent field." % (fieldName, interfaceName, name)) interface = None field = None # Find field and value nodes field_node = None value_node = None for child in node: if not isinstance(child.tag, str): continue elif child.tag.lower() == 'field': field_node = child elif child.tag.lower() == 'value': value_node = child # Let field not potentially override interface[fieldName] if field_node is not None: field_ref = field_node.attrib.get('ref', None) if field_ref is not None: # We have a field reference if field_ref not in self.context: raise KeyError( u"Record %s references field for record %s, \ which does not exist" % (name, field_ref)) ref_record = self.context.records[field_ref] field = FieldRef(field_ref, ref_record.field) else: # We have a standard field field_type = field_node.attrib.get('type', None) field_type_handler = queryUtility(IFieldExportImportHandler, name=field_type) if field_type_handler is None: raise TypeError( "Field of type %s used for record %s is not supported." % (field_type, name)) else: field = field_type_handler.read(field_node) if not IPersistentField.providedBy(field): raise TypeError( "Only persistent fields may be imported. \ %s used for record %s is invalid." % (field_type, name)) if field is not None and not IFieldRef.providedBy(field): # Set interface name and fieldName, if applicable field.interfaceName = interfaceName field.fieldName = fieldName # Fall back to existing record if neither a field node nor the # interface yielded a field change_field = True if field is None and existing_record is not None: change_field = False field = existing_record.field if field is None: raise ValueError("Cannot find a field for the record %s. Add a \ <field /> element or reference an interface and field name." % name) # Extract the value if value_node is not None: value_purge = value_node.attrib.get('purge', '').lower() != 'false' value = elementToValue(field, value_node, default=_marker) # Now either construct or update the record if value is _marker: value = field.default value_purge = True if existing_record is not None: if change_field: existing_record.field = field existing_value = existing_record.value if change_field or value != existing_value: if not value_purge and type(value) == type(existing_value): if isinstance(value, list): value = existing_value + [ v for v in value if v not in existing_value ] elif isinstance(value, tuple): value = existing_value + tuple( [v for v in value if v not in existing_value]) elif isinstance(value, ( set, frozenset, )): value = existing_value.union(value) elif isinstance(value, dict): for key, value in value.items(): # check if value is list, if so, let's add # instead of overridding if type(value) == list: if key in existing_value and \ not shouldPurgeList(value_node, key): existing = existing_value[key] for item in existing: # here, we'll remove existing items # point is that we don't want duplicates # and don't want to reorder if item in value: value.remove(item) existing.extend(value) value = existing existing_value[key] = value value = existing_value existing_record.value = value else: self.context.records[name] = Record(field, value)
def importRecord(self, node): name = node.get('name', '') delete = node.get('delete', 'false') interfaceName = node.get('interface', None) fieldName = node.get('field', None) if not name and (interfaceName and fieldName): prefix = node.get('prefix', None) if prefix is None: prefix = interfaceName name = "%s.%s" % (prefix, fieldName,) if not name: raise NameError("No name given for <record /> node!") # Unicode is not supported name = str(name) # Handle deletion and quit if delete.lower() == 'true': if name in self.context.records: del self.context.records[name] self.logger.info("Deleted record %s." % name) else: self.logger.warning("Record %s was marked for deletion, but was not found." % name) return # See if we have an existing record existing_record = self.context.records.get(name, None) interface = None field = None value = _marker value_purge = True # If we are given an interface and field name, try to resolve them if interfaceName and fieldName: try: interface = resolve(interfaceName) field = IPersistentField(interface[fieldName]) except ImportError: self.logger.warning("Failed to import interface %s for record %s" % (interfaceName, name)) interface = None field = None except KeyError: self.logger.warning("Interface %s specified for record %s has no field %s." % (interfaceName, name, fieldName,)) interface = None field = None except TypeError: self.logger.warning("Field %s in interface %s specified for record %s cannot be used as a persistent field." % (fieldName, interfaceName, name,)) interface = None field = None # Find field and value nodes field_node = None value_node = None for child in node: if child.tag.lower() == 'field': field_node = child elif child.tag.lower() == 'value': value_node = child # Let field not potentially override interface[fieldName] if field_node is not None: field_ref = field_node.attrib.get('ref', None) if field_ref is not None: # We have a field reference if field_ref not in self.context: raise KeyError(u"Record %s references field for record %s, which does not exist" % (name, field_ref,)) ref_record = self.context.records[field_ref] field = FieldRef(field_ref, ref_record.field) else: # We have a standard field field_type = field_node.attrib.get('type', None) field_type_handler = queryUtility(IFieldExportImportHandler, name=field_type) if field_type_handler is None: raise TypeError("Field of type %s used for record %s is not supported." % (field_type, name,)) else: field = field_type_handler.read(field_node) if not IPersistentField.providedBy(field): raise TypeError("Only persistent fields may be imported. %s used for record %s is invalid." % (field_type, name,)) if field is not None and not IFieldRef.providedBy(field): # Set interface name and fieldName, if applicable field.interfaceName = interfaceName field.fieldName = fieldName # Fall back to existing record if neither a field node nor the # interface yielded a field change_field = True if field is None and existing_record is not None: change_field = False field = existing_record.field if field is None: raise ValueError("Cannot find a field for the record %s. Add a <field /> element or reference an interface and field name." % name) # Extract the value if value_node is not None: value_purge = value_node.attrib.get('purge', '').lower() != 'false' value = elementToValue(field, value_node, default=_marker) # Now either construct or update the record if value is _marker: value = field.default value_purge = True if existing_record is not None: if change_field: existing_record.field = field existing_value = existing_record.value if change_field or value != existing_value: if not value_purge and type(value) == type(existing_value): if isinstance(value, list): value = existing_value + [v for v in value if v not in existing_value] elif isinstance(value, tuple): value = existing_value + tuple([v for v in value if v not in existing_value]) elif isinstance(value, (set, frozenset,)): value = existing_value.union(value) elif isinstance(value, dict): existing_value.update(value) value = existing_value existing_record.value = value else: self.context.records[name] = Record(field, value)