Skip to content

validate_references

xsdata.codegen.handlers.validate_references

ValidateReferences

Bases: ContainerHandlerInterface

Validate type references.

Rules
  • An extension, type, restriction can not be shared
  • All user types have to match the reference number and qualified name of a class.
  • All global class qualified names must be unique
Source code in xsdata/codegen/handlers/validate_references.py
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
class ValidateReferences(ContainerHandlerInterface):
    """Validate type references.

    Rules:
        - An extension, type, restriction can not be shared
        - All user types have to match the reference number
          and qualified name of a class.
        - All global class qualified names must be unique
    """

    def run(self):
        """Validate type references."""
        self.validate_unique_qualified_names()
        self.validate_unique_instances()
        self.validate_resolved_references()
        self.validate_parent_references()

    def validate_unique_qualified_names(self):
        """Validate all root classes have unique qualified names."""
        duplicate_types = []
        groups = collections.group_by(self.container, get_qname)
        for qname, items in groups.items():
            if len(items) > 1:
                duplicate_types.append(qname)

        if duplicate_types:
            raise CodegenError("Duplicate types found", qnames=duplicate_types)

    def validate_unique_instances(self):
        """Validate all codegen instances are unique."""
        references: Set[int] = set()
        for item in self.container:
            item_references = {id(child) for child in item.children()}
            if item_references.intersection(references):
                raise CodegenError("Cross reference detected", type=item.qname)

            references.update(item_references)

    def validate_resolved_references(self):
        """Validate all types match a class reference and qualified name."""

        def build_reference_map():
            def build(target: Class):
                yield target.ref, target.qname

                for inner in target.inner:
                    yield from build(inner)

            for target in self.container:
                yield from build(target)

        references = dict(build_reference_map())
        for item in self.container:
            for tp in item.types():
                if tp.native:
                    continue

                if tp.reference not in references:
                    raise CodegenError(
                        "Unresolved reference detected", cls=item.qname, type=tp.qname
                    )

                if tp.qname != references[tp.reference]:
                    raise CodegenError(
                        "Misrepresented reference", cls=item.qname, type=tp.qname
                    )

    def validate_parent_references(self):
        """Validate inner to outer classes is accurate."""

        def _validate(target: Class, parent: Optional[Class] = None):
            actual_qname = actual_ref = expected_qname = expected_ref = None
            if target.parent:
                actual_qname = target.parent.qname
                actual_ref = target.parent.ref

            if parent:
                expected_qname = parent.qname
                expected_ref = parent.ref

            if actual_qname != expected_qname:
                raise CodegenError(
                    "Invalid parent class reference",
                    cls=target.qname,
                    expected=expected_qname,
                    actual=actual_qname,
                )

            if actual_ref != expected_ref:
                raise CodegenError(
                    "Invalid parent class reference",
                    cls=target.qname,
                    ref=actual_qname,
                )

            for inner in target.inner:
                _validate(inner, target)

        for item in self.container:
            _validate(item)

run()

Validate type references.

Source code in xsdata/codegen/handlers/validate_references.py
19
20
21
22
23
24
def run(self):
    """Validate type references."""
    self.validate_unique_qualified_names()
    self.validate_unique_instances()
    self.validate_resolved_references()
    self.validate_parent_references()

validate_unique_qualified_names()

Validate all root classes have unique qualified names.

Source code in xsdata/codegen/handlers/validate_references.py
26
27
28
29
30
31
32
33
34
35
def validate_unique_qualified_names(self):
    """Validate all root classes have unique qualified names."""
    duplicate_types = []
    groups = collections.group_by(self.container, get_qname)
    for qname, items in groups.items():
        if len(items) > 1:
            duplicate_types.append(qname)

    if duplicate_types:
        raise CodegenError("Duplicate types found", qnames=duplicate_types)

validate_unique_instances()

Validate all codegen instances are unique.

Source code in xsdata/codegen/handlers/validate_references.py
37
38
39
40
41
42
43
44
45
def validate_unique_instances(self):
    """Validate all codegen instances are unique."""
    references: Set[int] = set()
    for item in self.container:
        item_references = {id(child) for child in item.children()}
        if item_references.intersection(references):
            raise CodegenError("Cross reference detected", type=item.qname)

        references.update(item_references)

validate_resolved_references()

Validate all types match a class reference and qualified name.

Source code in xsdata/codegen/handlers/validate_references.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def validate_resolved_references(self):
    """Validate all types match a class reference and qualified name."""

    def build_reference_map():
        def build(target: Class):
            yield target.ref, target.qname

            for inner in target.inner:
                yield from build(inner)

        for target in self.container:
            yield from build(target)

    references = dict(build_reference_map())
    for item in self.container:
        for tp in item.types():
            if tp.native:
                continue

            if tp.reference not in references:
                raise CodegenError(
                    "Unresolved reference detected", cls=item.qname, type=tp.qname
                )

            if tp.qname != references[tp.reference]:
                raise CodegenError(
                    "Misrepresented reference", cls=item.qname, type=tp.qname
                )

validate_parent_references()

Validate inner to outer classes is accurate.

Source code in xsdata/codegen/handlers/validate_references.py
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def validate_parent_references(self):
    """Validate inner to outer classes is accurate."""

    def _validate(target: Class, parent: Optional[Class] = None):
        actual_qname = actual_ref = expected_qname = expected_ref = None
        if target.parent:
            actual_qname = target.parent.qname
            actual_ref = target.parent.ref

        if parent:
            expected_qname = parent.qname
            expected_ref = parent.ref

        if actual_qname != expected_qname:
            raise CodegenError(
                "Invalid parent class reference",
                cls=target.qname,
                expected=expected_qname,
                actual=actual_qname,
            )

        if actual_ref != expected_ref:
            raise CodegenError(
                "Invalid parent class reference",
                cls=target.qname,
                ref=actual_qname,
            )

        for inner in target.inner:
            _validate(inner, target)

    for item in self.container:
        _validate(item)