author Denis Laxalde <>
Thu, 02 May 2019 09:29:04 +0200
changeset 3003 fcb890e6d9d7
parent 2899 ed666cbea6af
child 3021 2212adf2c673
permissions -rw-r--r--
[profile gen] Account for bdo's user cardinality or its parent's in "Integrity" element (CONSEJIRA-663) See also For more details, quoting verbatim the customer request for future reference: | Sur les documents multi occurrences (0-n ou 1-n) ou même si l’archive | est multi occurrence (0-n ou 1-n), il y a une balise integrity qui est | liée au document dans le bordereau de versement que l’on génère. | Or, dans le XSD du profil, la balise integrity du document ne possède | pas l'attribut : maxOccurs="unbounded" | Donc lors de l'envoi à Asalae du versement, Asalae fait une vérification | par rapport au profil et affiche une erreur a cause de la balise | integrity qui est présente plusieurs fois. | | Pour moi le correctif à faire doit porter sur le XSD et le RNG sur la | balise integrity pour qu'elle soit multi-occurrence possible dans les cas | suivants : | | * Si le document (Document) est en multi occurrence (0-n ou 1-n) | donc avec un attribut maxOccurs="unbounded" | * Si une UA (Contains) supérieure au document est en multi | occurrence (0-n ou 1-n) donc avec un attribut | maxOccurs="unbounded" | si une UA supérieur est en cardinalité max unbounded, alors | l'integrity sur les documents en dessous doit forcément être en | unbounded également | il faut que l'integrity soit en facultative ou multi occurrence si une | UA supérieure est facultative ou en multi occurrence. This is essentially achieved by looking for the upper parent archive units of a data object then their cardinality to produce the Integrity element. Adding tests for new integrity_cardinality() function based on customer examples.

# copyright 2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact --
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
# You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see <>.
"""Generate CubicWeb's entities from XSD file"""

import json

from xsd2yams import MULTIPLE_CHILDREN, CodeGenerator
from xsd2uicfg import ordered_attributes

MULTIPLE_ETYPES = set(etype for etype, _ in MULTIPLE_CHILDREN)

TEMPLATE = '''class {etype}(SEDAAnyEntity):
    __regid__ = '{etype}'
    fetch_attrs, cw_fetch_order = fetch_config({attributes})
    value_attr = {value_attribute}

class EntitiesGenerator(CodeGenerator):

    def _generate(self, mapping, stream):
        stream.write('from cubicweb.entities import AnyEntity, fetch_config\n\n')
class SEDAAnyEntity(AnyEntity):
    __abstract__ = True
    value_attr = None

    def dc_title(self):
        if self.value_attr is None:
            return self.dc_type()
        return self.printable_value(self.value_attr)

        self.altetype2rtype = {}  # rtype to children elements for all choices
        self.check_card_etypes = set()  # entity types whose cardinality must be checked
        self.check_card_rtypes = set()  # relation types whose children cardinality must be checked
        for mapping_element in mapping.ordered:
            self._callback('register_alt_rtype_for', mapping_element)
            eclass_code = self._callback('entity_class_for', mapping_element)
            if eclass_code:
                stream.write(eclass_code + '\n')
        # Write pre-computed data structures as constants
        for name, data in [('CHOICE_RTYPE', self.altetype2rtype),
                           ('CHECK_CARD_ETYPES', sorted(self.check_card_etypes)),
                           ('CHECK_CHILDREN_CARD_RTYPES', sorted(self.check_card_rtypes))]:
            stream.write(u'{} = '.format(name))
            stream.write(json.dumps(data, sort_keys=True, indent=2,
                                    separators=(',', ': ')).replace('"', "'") + '\n')

    def entity_class_for_e_type_mapping(self, mapping):
        attributes = ordered_attributes(mapping)
        value_attribute = None
        if mapping.etype in ('SEDAArchiveUnit', 'SEDABinaryDataObject', 'SEDAPhysicalDataObject'):
        elif mapping.attributes:
            value_attribute = next(iter(mapping.attributes))
        elif and len( > 1:
            attributes = ['user_cardinality']
        if mapping.etype in MULTIPLE_ETYPES:
            attributes.insert(0, 'ordering')
        return TEMPLATE.format(etype=mapping.etype,

    def register_alt_rtype_for_rdef_mapping(self, mapping):
        composite = mapping.composite
        if not composite:
        altetypes = mapping.objtypes if composite == 'object' else [mapping.subjtype]
        for altetype in altetypes:
            if altetype.startswith('SEDAAlt'):
                self.altetype2rtype.setdefault(altetype, []).append((mapping.rtype, composite))

        if mapping.card[1] in '*+':

if __name__ == '__main__':