示例#1
0
    def generateInterface(self):
        logger.debug('generating interface for %s' % self.short_name)

        if hasattr(self, 'is_single_select') and self.is_single_select:
            select_field = schema.Choice(title=_(unicode(self.field_title)),
                                         description=_(
                                             unicode(self.field_description)),
                                         required=self.is_required,
                                         vocabulary=self.vocabulary_name)
        else:
            select_field = schema.List(
                title=_(unicode(self.field_title)),
                description=_(unicode(self.field_description)),
                required=self.is_required,
                min_length=self.is_required and 1 or 0,
                value_type=schema.Choice(vocabulary=self.vocabulary_name,
                                         required=self.is_required))

        schemaclass = SchemaClass(self.short_name, (Schema, ),
                                  __module__='collective.taxonomy.generated',
                                  attrs={str(self.field_name): select_field})

        if self.write_permission:
            schemaclass.setTaggedValue(
                WRITE_PERMISSIONS_KEY,
                {self.field_name: self.write_permission})

        schemaclass.setTaggedValue(FIELDSETS_KEY, [
            Fieldset('categorization',
                     label=_pmf(u'label_schema_categorization',
                                default=u'Categorization'),
                     fields=[self.field_name])
        ])

        #        if hasattr(self, 'is_single_select') and not self.is_single_select:
        #            schemaclass.setTaggedValue(
        #                WIDGETS_KEY,
        #                {self.field_name:
        #                 'collective.taxonomy.widget.TaxonomySelectFieldWidget'}
        #            )
        if hasattr(self, 'is_single_select') and not self.is_single_select:
            if hasattr(self, 'has_query_widget') and self.has_query_widget:
                schemaclass.setTaggedValue(
                    WIDGETS_KEY, {
                        self.field_name:
                        'plone.formwidget.autocomplete.widget.AutocompleteMultiFieldWidget'
                    })
            else:
                schemaclass.setTaggedValue(
                    WIDGETS_KEY, {
                        self.field_name:
                        'collective.taxonomy.widget.TaxonomySelectFieldWidget'
                    })

        alsoProvides(schemaclass, IFormFieldProvider)
        return schemaclass
示例#2
0
def copy_schema(schema, filter_serializable=False):
    fields = {}
    for item in schema:
        if (filter_serializable and not is_serialisable_field(schema[item])):
            continue
        fields[item] = schema[item]
    oschema = SchemaClass(SCHEMATA_KEY, attrs=fields)
    # copy base tagged values
    for i in schema.getTaggedValueTags():
        oschema.setTaggedValue(item, schema.queryTaggedValue(i))
    finalizeSchemas(oschema)
    return oschema
示例#3
0
    def generateInterface(self):
        logger.debug('generating interface for %s' % self.short_name)

        if hasattr(self, 'is_single_select') and self.is_single_select:
            select_field = schema.Choice(
                title=_(unicode(self.field_title)),
                description=_(unicode(self.field_description)),
                required=self.is_required,
                vocabulary=self.vocabulary_name
            )
        else:
            select_field = schema.List(
                title=_(unicode(self.field_title)),
                description=_(unicode(self.field_description)),
                required=self.is_required,
                min_length=self.is_required and 1 or 0,
                value_type=schema.Choice(
                    vocabulary=self.vocabulary_name,
                    required=self.is_required
                )
            )

        schemaclass = SchemaClass(
            self.short_name, (Schema,),
            __module__='collective.taxonomy.generated',
            attrs={
                str(self.field_name): select_field
            }
        )

        if self.write_permission:
            schemaclass.setTaggedValue(
                WRITE_PERMISSIONS_KEY,
                {self.field_name:
                 self.write_permission}
            )

        schemaclass.setTaggedValue(
            FIELDSETS_KEY,
            [Fieldset('categorization',
                      label=_pmf(u'label_schema_categorization', default=u'Categorization'),
                      fields=[self.field_name])]
        )

        # if hasattr(self, 'is_single_select') and not self.is_single_select:
        #    schemaclass.setTaggedValue(
        #        WIDGETS_KEY,
        #        {self.field_name:
        #         'collective.taxonomy.widget.TaxonomySelectFieldWidget'}
        #    )

        alsoProvides(schemaclass, IFormFieldProvider)
        return schemaclass
示例#4
0
def copy_schema(schema, filter_serializable=False):
    fields = {}
    for item in schema:
        if filter_serializable and not is_serialisable_field(schema[item]):
            continue
        fields[item] = schema[item]
    oschema = SchemaClass(SCHEMATA_KEY, attrs=fields)
    # copy base tagged values
    for i in schema.getTaggedValueTags():
        oschema.setTaggedValue(item, schema.queryTaggedValue(i))
    finalizeSchemas(oschema)
    return oschema
示例#5
0
def upgrade_to_ttw(context):
    # the new default schema only contains fullname and email fields
    # so we put the missing ones (home_page, description, location, portrait)
    # into the ttw schema
    if schemaeditor.get_schema() == '':
        finalizeSchemas(IEmpty)
        current_ttw = IEditableSchema(IEmpty)
    else:
        current_ttw = IEditableSchema(schemaeditor.load_ttw_schema())

    attrs = copySchemaAttrs(current_ttw.schema)
    current_fields = current_ttw.schema.names()
    pm = getToolByName(context, "portal_memberdata")
    existing = pm.propertyIds()

    if 'home_page' in existing and 'home_page' not in current_fields:
        attrs.update(copySchemaAttrs(IHomePageSchema))

    if 'description' in existing and 'description' not in current_fields:
        attrs.update(copySchemaAttrs(IDescriptionSchema))

    if 'location' in existing and 'location' not in current_fields:
        attrs.update(copySchemaAttrs(ILocationSchema))

    if 'portrait' in existing and 'portrait' not in current_fields:
        attrs.update(copySchemaAttrs(IPortraitSchema))

    sch = SchemaClass(schemaeditor.SCHEMATA_KEY,
                      bases=(current_ttw.schema, ),
                      attrs=attrs)
    finalizeSchemas(sch)

    xml_model = schemaeditor.serialize_ttw_schema(sch)
    schemaeditor.set_schema(xml_model)
    log.info('Old member fields migrated into TTW schema')
示例#6
0
    def __getattr__(self, name):
        if name.startswith("__"):
            return getattr(self.__dict__["wrapped"], name)

        if not hasattr(self.__dict__["wrapped"], name):
            sm = getSite().getSiteManager()

            utility = sm.queryUtility(IBehavior,
                                      name="collective.taxonomy.generated." +
                                      name)

            if utility:
                setattr(self.__dict__["wrapped"], name,
                        utility.generateInterface())
            else:
                setattr(
                    self.__dict__["wrapped"],
                    name,
                    SchemaClass(
                        name,
                        (Schema, ),
                        __module__="collective.taxonomy.generated",
                        attrs={},
                    ),
                )

        return getattr(self.__dict__["wrapped"], name)
示例#7
0
    def generateInterface(self):
        logger.debug("generating interface for %s" % self.short_name)

        if hasattr(self, "is_single_select") and self.is_single_select:
            select_field = schema.Choice(
                title=_(safe_unicode(self.field_title)),
                description=_(safe_unicode(self.field_description)),
                required=self.is_required,
                vocabulary=self.vocabulary_name,
            )
        else:
            select_field = schema.List(
                title=_(safe_unicode(self.field_title)),
                description=_(safe_unicode(self.field_description)),
                required=self.is_required,
                min_length=self.is_required and 1 or 0,
                value_type=schema.Choice(
                    vocabulary=self.vocabulary_name, required=self.is_required
                ),
            )

        schemaclass = SchemaClass(
            self.short_name,
            (Schema,),
            __module__="collective.taxonomy.generated",
            attrs={str(self.field_name): select_field},
        )

        if self.write_permission:
            schemaclass.setTaggedValue(
                WRITE_PERMISSIONS_KEY, {self.field_name: self.write_permission}
            )

        try:
            taxonomy_fieldset = self.taxonomy_fieldset
        except AttributeError:
            # Backwards compatible:
            taxonomy_fieldset = "categorization"
        if taxonomy_fieldset != "default":
            schemaclass.setTaggedValue(
                FIELDSETS_KEY, [Fieldset(taxonomy_fieldset, fields=[self.field_name])]
            )

        if hasattr(self, "is_single_select") and not self.is_single_select:
            schemaclass.setTaggedValue(
                WIDGETS_KEY,
                {
                    self.field_name: "collective.taxonomy.widget.TaxonomySelectFieldWidget"
                },
            )

        alsoProvides(schemaclass, IFormFieldProvider)

        if HAS_PAM:
            alsoProvides(schemaclass[self.field_name], ILanguageIndependentField)

        return schemaclass
def getFromBaseSchema(baseSchema, form_name=None):
    attrs = copySchemaAttrs(baseSchema, form_name)
    ttwschema = get_ttw_edited_schema()
    if ttwschema:
        attrs.update(copySchemaAttrs(ttwschema, form_name))
    schema = SchemaClass(SCHEMATA_KEY, bases=(baseSchema, ), attrs=attrs)
    finalizeSchemas(schema)
    return schema
    def generateInterface(self):
        logger.debug('generating interface for %s' % self.short_name)

        if hasattr(self, 'is_single_select') and self.is_single_select:
            select_field = schema.Choice(
                title=_(safe_unicode(self.field_title)),
                description=_(safe_unicode(self.field_description)),
                required=self.is_required,
                vocabulary=self.vocabulary_name
            )
        else:
            select_field = schema.List(
                title=_(safe_unicode(self.field_title)),
                description=_(safe_unicode(self.field_description)),
                required=self.is_required,
                min_length=self.is_required and 1 or 0,
                value_type=schema.Choice(
                    vocabulary=self.vocabulary_name,
                    required=self.is_required
                )
            )

        schemaclass = SchemaClass(
            self.short_name, (Schema, ),
            __module__='collective.taxonomy.generated',
            attrs={
                str(self.field_name): select_field
            }
        )

        if self.write_permission:
            schemaclass.setTaggedValue(
                WRITE_PERMISSIONS_KEY,
                {self.field_name:
                 self.write_permission}
            )

        try:
            taxonomy_fieldset = self.taxonomy_fieldset
        except AttributeError:
            # Backwards compatible:
            taxonomy_fieldset = 'categorization'
        if taxonomy_fieldset != 'default':
            schemaclass.setTaggedValue(
                FIELDSETS_KEY,
                [Fieldset(taxonomy_fieldset,
                          fields=[self.field_name])]
            )

        if hasattr(self, 'is_single_select') and not self.is_single_select:
            schemaclass.setTaggedValue(
                WIDGETS_KEY,
                {self.field_name:
                 'collective.taxonomy.widget.TaxonomySelectFieldWidget'}
            )

        alsoProvides(schemaclass, IFormFieldProvider)
        return schemaclass
示例#10
0
    def generateInterface(self):
        logger.debug('generating interface for %s' % self.short_name)

        if self.is_required:
            select_field = schema.List(
                title=_(unicode(self.field_title)),
                description=_(unicode(self.field_description)),
                required=True,
                constraint=lambda value: bool(value),

                value_type=schema.Choice(
                    vocabulary=self.vocabulary_name,
                    required=True
                )
            )
        else:
            select_field = schema.List(
                title=_(unicode(self.field_title)),
                description=_(unicode(self.field_description)),
                required=False,
                value_type=schema.Choice(
                    vocabulary=self.vocabulary_name,
                    required=False
                )
            )

        schemaclass = SchemaClass(
            self.short_name, (form.Schema, ),
            __module__='collective.taxonomy.generated',
            attrs={str(self.field_name):
                   select_field }
        )

        if self.write_permission:
            schemaclass.setTaggedValue(
                WRITE_PERMISSIONS_KEY,
                {self.field_name:
                 self.write_permission}
            )

        schemaclass.setTaggedValue(
            FIELDSETS_KEY,
            [Fieldset('categorization',
                      fields=[self.field_name])]
        )

        schemaclass.setTaggedValue(
            WIDGETS_KEY,
            {self.field_name:
             'collective.taxonomy.widget.TaxonomySelectFieldWidget'}
        )

        alsoProvides(schemaclass, form.IFormFieldProvider)
        return schemaclass
def serialize_ttw_schema(schema=None):
    if not schema:
        schema = get_ttw_edited_schema()
    bfields = [a for a in IUserDataSchema]
    attrs = {}
    for name in schema:
        f = schema[name]
        if is_serialisable_field(f) and name not in bfields:
            attrs[name] = f
    smember = SchemaClass(SCHEMATA_KEY, attrs=attrs)
    finalizeSchemas(smember)
    model = Model({SCHEMATA_KEY: smember})
    sschema = serialize(model)
    return sschema
示例#12
0
    def getSchema(self):
        """
        """
        def copySchemaAttrs(schema):
            return dict([(a, copy.deepcopy(schema[a])) for a in schema])

        attrs = copySchemaAttrs(self.baseSchema)
        ttwschema = get_ttw_edited_schema()
        if ttwschema:
            attrs.update(copySchemaAttrs(ttwschema))
        schema = SchemaClass(SCHEMATA_KEY,
                             bases=(self.baseSchema, ),
                             attrs=attrs)
        finalizeSchemas(schema)
        return schema
    def generateInterface(self):
        logger.debug('generating interface for %s' % self.short_name)

        if hasattr(self, 'is_single_select') and self.is_single_select:
            select_field = schema.Choice(title=_(unicode(self.field_title)),
                                         description=_(
                                             unicode(self.field_description)),
                                         required=self.is_required,
                                         vocabulary=self.vocabulary_name)
        else:
            select_field = schema.List(
                title=_(unicode(self.field_title)),
                description=_(unicode(self.field_description)),
                required=self.is_required,
                min_length=self.is_required and 1 or 0,
                value_type=schema.Choice(vocabulary=self.vocabulary_name,
                                         required=self.is_required))

        schemaclass = SchemaClass(self.short_name, (Schema, ),
                                  __module__='collective.taxonomy.generated',
                                  attrs={str(self.field_name): select_field})

        if self.write_permission:
            schemaclass.setTaggedValue(
                WRITE_PERMISSIONS_KEY,
                {self.field_name: self.write_permission})

        try:
            taxonomy_fieldset = self.taxonomy_fieldset
        except AttributeError:
            # Backwards compatible:
            taxonomy_fieldset = 'categorization'
        if taxonomy_fieldset != 'default':
            schemaclass.setTaggedValue(
                FIELDSETS_KEY,
                [Fieldset(taxonomy_fieldset, fields=[self.field_name])])

        if hasattr(self, 'is_single_select') and not self.is_single_select:
            schemaclass.setTaggedValue(
                WIDGETS_KEY, {
                    self.field_name:
                    'collective.taxonomy.widget.TaxonomySelectFieldWidget'
                })

        alsoProvides(schemaclass, IFormFieldProvider)
        return schemaclass
示例#14
0
    def get_schema(self, tile_id):
        widget_tags = {}
        fields = OrderedDict()
        for field_name, (factory,
                         data) in self.get_tile_fields(tile_id).items():
            if isinstance(factory, dict):
                if 'widget' in factory:
                    widget_tags[field_name] = factory['widget']
                if 'options' in factory:
                    data.update(factory['options'])
                factory = factory['factory']
            fields[field_name] = factory(**data)

        schema = SchemaClass(
            name=tile_id,
            bases=(IDynamicTileSchema, ),
            # we're mimicking plone.supermodel here so let's us
            # same module
            __module__='plone.supermodel.generated',
            attrs=fields)
        schema.setTaggedValue(WIDGETS_KEY, widget_tags)
        return schema
示例#15
0
def _parse(source, policy):
    tree = etree.parse(source)
    root = tree.getroot()

    parseinfo.i18n_domain = root.attrib.get(ns('domain', prefix=I18N_NAMESPACE))

    model = Model()

    handlers = {}
    schema_metadata_handlers = tuple(getUtilitiesFor(ISchemaMetadataHandler))
    field_metadata_handlers = tuple(getUtilitiesFor(IFieldMetadataHandler))

    policy_util = getUtility(ISchemaPolicy, name=policy)

    def readField(fieldElement, schemaAttributes, fieldElements, baseFields):

        # Parse field attributes
        fieldName = fieldElement.get('name')
        fieldType = fieldElement.get('type')

        if fieldName is None or fieldType is None:
            raise ValueError("The attributes 'name' and 'type' are required for each <field /> element")

        handler = handlers.get(fieldType, None)
        if handler is None:
            handler = handlers[fieldType] = queryUtility(IFieldExportImportHandler, name=fieldType)
            if handler is None:
                raise ValueError("Field type %s specified for field %s is not supported" % (fieldType, fieldName, ))

        field = handler.read(fieldElement)

        # Preserve order from base interfaces if this field is an override
        # of a field with the same name in a base interface
        base_field = baseFields.get(fieldName, None)
        if base_field is not None:
            field.order = base_field.order

        # Save for the schema
        schemaAttributes[fieldName] = field
        fieldElements[fieldName] = fieldElement

        return fieldName

    for schema_element in root.findall(ns('schema')):
        parseinfo.stack.append(schema_element)
        schemaAttributes = {}

        schemaName = schema_element.get('name')
        if schemaName is None:
            schemaName = u""

        bases = ()
        baseFields = {}
        based_on = schema_element.get('based-on')
        if based_on is not None:
            bases = tuple([resolve(dotted) for dotted in based_on.split()])
            for base_schema in bases:
                baseFields.update(getFields(base_schema))

        fieldElements = {}

        # Read global fields
        for fieldElement in schema_element.findall(ns('field')):
            parseinfo.stack.append(fieldElement)
            readField(fieldElement, schemaAttributes, fieldElements, baseFields)
            parseinfo.stack.pop()

        # Read fieldsets and their fields
        fieldsets = []
        fieldsets_by_name = {}

        for subelement in schema_element:
            parseinfo.stack.append(subelement)

            if subelement.tag == ns('field'):
                readField(subelement, schemaAttributes, fieldElements, baseFields)
            elif subelement.tag == ns('fieldset'):

                fieldset_name = subelement.get('name')
                if fieldset_name is None:
                    raise ValueError(u"Fieldset in schema %s has no name" % (schemaName))

                fieldset = fieldsets_by_name.get(fieldset_name, None)
                if fieldset is None:
                    fieldset_label = subelement.get('label')
                    fieldset_description = subelement.get('description')

                    fieldset = fieldsets_by_name[fieldset_name] = Fieldset(fieldset_name,
                                    label=fieldset_label, description=fieldset_description)
                    fieldsets_by_name[fieldset_name] = fieldset
                    fieldsets.append(fieldset)

                for fieldElement in subelement.findall(ns('field')):
                    parseinfo.stack.append(fieldElement)
                    parsed_fieldName = readField(fieldElement, schemaAttributes, fieldElements, baseFields)
                    if parsed_fieldName:
                        fieldset.fields.append(parsed_fieldName)
                    parseinfo.stack.pop()
            parseinfo.stack.pop()

        schema = SchemaClass(name=policy_util.name(schemaName, tree),
                                bases=bases + policy_util.bases(schemaName, tree) + (Schema,),
                                __module__=policy_util.module(schemaName, tree),
                                attrs=schemaAttributes)

        schema.setTaggedValue(FIELDSETS_KEY, fieldsets)

        # Save fieldsets

        # Let metadata handlers write metadata
        for handler_name, metadata_handler in field_metadata_handlers:
            for fieldName in schema:
                if fieldName in fieldElements:
                    metadata_handler.read(fieldElements[fieldName], schema, schema[fieldName])

        for handler_name, metadata_handler in schema_metadata_handlers:
            metadata_handler.read(schema_element, schema)

        model.schemata[schemaName] = schema
        parseinfo.stack.pop()

    parseinfo.i18n_domain = None
    return model
示例#16
0
def _parse(source, policy):
    tree = etree.parse(source)
    root = tree.getroot()

    parseinfo.i18n_domain = root.attrib.get(
        ns('domain', prefix=I18N_NAMESPACE)
    )

    model = Model()

    handlers = {}
    schema_metadata_handlers = tuple(getUtilitiesFor(ISchemaMetadataHandler))
    field_metadata_handlers = tuple(getUtilitiesFor(IFieldMetadataHandler))

    policy_util = getUtility(ISchemaPolicy, name=policy)

    def readField(fieldElement, schemaAttributes, fieldElements, baseFields):

        # Parse field attributes
        fieldName = fieldElement.get('name')
        fieldType = fieldElement.get('type')

        if fieldName is None or fieldType is None:
            raise ValueError(
                'The attributes \'name\' and \'type\' are required for each '
                '<field /> element'
            )

        handler = handlers.get(fieldType, None)
        if handler is None:
            handler = handlers[fieldType] = queryUtility(
                IFieldExportImportHandler,
                name=fieldType
            )
            if handler is None:
                raise ValueError(
                    'Field type {0} specified for field {1} is not '
                    'supported'.format(fieldType, fieldName)
                )

        field = handler.read(fieldElement)

        # Preserve order from base interfaces if this field is an override
        # of a field with the same name in a base interface
        base_field = baseFields.get(fieldName, None)
        if base_field is not None:
            field.order = base_field.order

        # Save for the schema
        schemaAttributes[fieldName] = field
        fieldElements[fieldName] = fieldElement

        return fieldName

    for schema_element in root.findall(ns('schema')):
        parseinfo.stack.append(schema_element)
        schemaAttributes = {}

        schemaName = schema_element.get('name')
        if schemaName is None:
            schemaName = u""

        bases = ()
        baseFields = {}
        based_on = schema_element.get('based-on')
        if based_on is not None:
            bases = tuple([resolve(dotted) for dotted in based_on.split()])
            for base_schema in bases:
                baseFields.update(getFields(base_schema))

        fieldElements = {}

        # Read global fields
        for fieldElement in schema_element.findall(ns('field')):
            parseinfo.stack.append(fieldElement)
            readField(
                fieldElement,
                schemaAttributes,
                fieldElements,
                baseFields
            )
            parseinfo.stack.pop()

        # Read invariants, fieldsets and their fields
        invariants = []
        fieldsets = []
        fieldsets_by_name = {}

        for subelement in schema_element:
            parseinfo.stack.append(subelement)

            if subelement.tag == ns('field'):
                readField(
                    subelement,
                    schemaAttributes,
                    fieldElements,
                    baseFields
                )
            elif subelement.tag == ns('fieldset'):

                fieldset_name = subelement.get('name')
                if fieldset_name is None:
                    raise ValueError(
                        u'Fieldset in schema {0} has no name'.format(
                            schemaName
                        )
                    )

                fieldset = fieldsets_by_name.get(fieldset_name, None)
                if fieldset is None:
                    fieldset_label = subelement.get('label')
                    fieldset_description = subelement.get('description')
                    fieldset_order = subelement.get('order')
                    if fieldset_order is None:
                        fieldset_order = DEFAULT_ORDER
                    elif isinstance(fieldset_order, basestring):
                        fieldset_order = int(fieldset_order)
                    fieldset = fieldsets_by_name[fieldset_name] = Fieldset(
                        fieldset_name,
                        label=fieldset_label,
                        description=fieldset_description,
                        order=fieldset_order,
                    )
                    fieldsets_by_name[fieldset_name] = fieldset
                    fieldsets.append(fieldset)

                for fieldElement in subelement.findall(ns('field')):
                    parseinfo.stack.append(fieldElement)
                    parsed_fieldName = readField(
                        fieldElement,
                        schemaAttributes,
                        fieldElements,
                        baseFields
                    )
                    if parsed_fieldName:
                        fieldset.fields.append(parsed_fieldName)
                    parseinfo.stack.pop()
            elif subelement.tag == ns('invariant'):
                dotted = subelement.text
                invariant = resolve(dotted)
                if not IInvariant.providedBy(invariant):
                    raise ImportError(
                        u'Invariant functions must provide '
                        u'plone.supermodel.interfaces.IInvariant'
                    )
                invariants.append(invariant)
            parseinfo.stack.pop()

        schema = SchemaClass(
            name=policy_util.name(schemaName, tree),
            bases=bases + policy_util.bases(schemaName, tree) + (Schema,),
            __module__=policy_util.module(schemaName, tree),
            attrs=schemaAttributes
        )

        # add invariants to schema as tagged values
        if invariants:
            schema_invariants = schema.queryTaggedValue('invariants', [])
            schema.setTaggedValue('invariants', schema_invariants + invariants)

        # Save fieldsets
        schema.setTaggedValue(FIELDSETS_KEY, fieldsets)

        # Let metadata handlers write metadata
        for handler_name, metadata_handler in field_metadata_handlers:
            for fieldName in schema:
                if fieldName in fieldElements:
                    metadata_handler.read(
                        fieldElements[fieldName],
                        schema,
                        schema[fieldName]
                    )

        for handler_name, metadata_handler in schema_metadata_handlers:
            metadata_handler.read(schema_element, schema)

        model.schemata[schemaName] = schema
        parseinfo.stack.pop()

    parseinfo.i18n_domain = None
    return model
示例#17
0
def _parse(source, policy):
    tree = etree.parse(source)
    root = tree.getroot()

    parseinfo.i18n_domain = root.attrib.get(ns('domain',
                                               prefix=I18N_NAMESPACE))

    model = Model()

    handlers = {}
    schema_metadata_handlers = tuple(getUtilitiesFor(ISchemaMetadataHandler))
    field_metadata_handlers = tuple(getUtilitiesFor(IFieldMetadataHandler))

    policy_util = getUtility(ISchemaPolicy, name=policy)

    def readField(fieldElement, schemaAttributes, fieldElements, baseFields):

        # Parse field attributes
        fieldName = fieldElement.get('name')
        fieldType = fieldElement.get('type')

        if fieldName is None or fieldType is None:
            raise ValueError(
                'The attributes \'name\' and \'type\' are required for each '
                '<field /> element')

        handler = handlers.get(fieldType, None)
        if handler is None:
            handler = handlers[fieldType] = queryUtility(
                IFieldExportImportHandler, name=fieldType)
            if handler is None:
                raise ValueError(
                    'Field type {0} specified for field {1} is not '
                    'supported'.format(fieldType, fieldName))

        field = handler.read(fieldElement)

        # Preserve order from base interfaces if this field is an override
        # of a field with the same name in a base interface
        base_field = baseFields.get(fieldName, None)
        if base_field is not None:
            field.order = base_field.order

        # Save for the schema
        schemaAttributes[fieldName] = field
        fieldElements[fieldName] = fieldElement

        return fieldName

    for schema_element in root.findall(ns('schema')):
        parseinfo.stack.append(schema_element)
        schemaAttributes = {}

        schemaName = schema_element.get('name')
        if schemaName is None:
            schemaName = u""

        bases = ()
        baseFields = {}
        based_on = schema_element.get('based-on')
        if based_on is not None:
            bases = tuple([resolve(dotted) for dotted in based_on.split()])
            for base_schema in bases:
                baseFields.update(getFields(base_schema))

        fieldElements = {}

        # Read global fields
        for fieldElement in schema_element.findall(ns('field')):
            parseinfo.stack.append(fieldElement)
            readField(fieldElement, schemaAttributes, fieldElements,
                      baseFields)
            parseinfo.stack.pop()

        # Read invariants, fieldsets and their fields
        invariants = []
        fieldsets = []
        fieldsets_by_name = {}

        for subelement in schema_element:
            parseinfo.stack.append(subelement)

            if subelement.tag == ns('field'):
                readField(subelement, schemaAttributes, fieldElements,
                          baseFields)
            elif subelement.tag == ns('fieldset'):

                fieldset_name = subelement.get('name')
                if fieldset_name is None:
                    raise ValueError(
                        u'Fieldset in schema {0} has no name'.format(
                            schemaName))

                fieldset = fieldsets_by_name.get(fieldset_name, None)
                if fieldset is None:
                    fieldset_label = subelement.get('label')
                    fieldset_description = subelement.get('description')
                    fieldset_order = subelement.get('order')
                    if fieldset_order is None:
                        fieldset_order = DEFAULT_ORDER
                    elif isinstance(fieldset_order, six.string_types):
                        fieldset_order = int(fieldset_order)
                    fieldset = fieldsets_by_name[fieldset_name] = Fieldset(
                        fieldset_name,
                        label=fieldset_label,
                        description=fieldset_description,
                        order=fieldset_order,
                    )
                    fieldsets_by_name[fieldset_name] = fieldset
                    fieldsets.append(fieldset)

                for fieldElement in subelement.findall(ns('field')):
                    parseinfo.stack.append(fieldElement)
                    parsed_fieldName = readField(fieldElement,
                                                 schemaAttributes,
                                                 fieldElements, baseFields)
                    if parsed_fieldName:
                        fieldset.fields.append(parsed_fieldName)
                    parseinfo.stack.pop()
            elif subelement.tag == ns('invariant'):
                dotted = subelement.text
                invariant = resolve(dotted)
                if not IInvariant.providedBy(invariant):
                    raise ImportError(
                        u'Invariant functions must provide '
                        u'plone.supermodel.interfaces.IInvariant')
                invariants.append(invariant)
            parseinfo.stack.pop()

        schema = SchemaClass(name=policy_util.name(schemaName, tree),
                             bases=bases +
                             policy_util.bases(schemaName, tree) + (Schema, ),
                             __module__=policy_util.module(schemaName, tree),
                             attrs=schemaAttributes)

        # add invariants to schema as tagged values
        if invariants:
            schema_invariants = schema.queryTaggedValue('invariants', [])
            schema.setTaggedValue('invariants', schema_invariants + invariants)

        # Save fieldsets
        schema.setTaggedValue(FIELDSETS_KEY, fieldsets)

        # Let metadata handlers write metadata
        for handler_name, metadata_handler in field_metadata_handlers:
            for fieldName in schema:
                if fieldName in fieldElements:
                    metadata_handler.read(fieldElements[fieldName], schema,
                                          schema[fieldName])

        for handler_name, metadata_handler in schema_metadata_handlers:
            metadata_handler.read(schema_element, schema)

        model.schemata[schemaName] = schema
        parseinfo.stack.pop()

    parseinfo.i18n_domain = None
    return model