Skip to content

unnest_inner_classes

xsdata.codegen.handlers.unnest_inner_classes

UnnestInnerClasses

Bases: RelativeHandlerInterface

Promote inner classes to root classes.

Source code in xsdata/codegen/handlers/unnest_inner_classes.py
  8
  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
class UnnestInnerClasses(RelativeHandlerInterface):
    """Promote inner classes to root classes."""

    __slots__ = ()

    def process(self, target: Class):
        """Process entrypoint for classes.

        Process the target class inner classes recursively.

        All enumerations are promoted by default, otherwise
        only if the configuration is disabled the classes
        are ignored.

        Args:
            target: The target class instance to inspect
        """
        for inner in list(target.inner):
            if inner.is_enumeration or self.container.config.output.unnest_classes:
                self.promote(target, inner)

    def promote(self, target: Class, inner: Class):
        """Promote the inner class to root classes.

        Steps:
            - Replace forward references to the inner class
            - Remove inner class from target class
            - Copy the class to the global class container.

        Args:
            target: The target class
            inner: An inner class
        """
        target.inner.remove(inner)
        attr = self.find_forward_attr(target, inner.qname)
        if attr:
            clone = self.clone_class(inner, target.name)
            self.update_types(attr, inner.qname, clone)
            self.container.add(clone)

    @classmethod
    def clone_class(cls, inner: Class, name: str) -> Class:
        """Clone and prepare inner class for promotion.

        Clone the inner class, mark it as promoted and pref
        the qualified name with the parent class name.

        Args:
            inner: The inner class to clone and prepare
            name: The parent class name to use a prefix

        Returns:
            The new class instance
        """
        clone = inner.clone()
        clone.parent = None
        clone.local_type = True
        clone.qname = build_qname(inner.target_namespace, f"{name}_{inner.name}")

        for attr in clone.attrs:
            for tp in attr.types:
                if tp.circular and tp.qname == inner.qname:
                    tp.qname = clone.qname
                    tp.reference = clone.ref

        return clone

    @classmethod
    def update_types(cls, attr: Attr, search: str, source: Class):
        """Update the references from an inner to a global class.

        Args:
            attr: The target attr to inspect and update
            search: The current inner class qname
            source: The new global class qname
        """
        for attr_type in attr.types:
            if attr_type.qname == search and attr_type.forward:
                attr_type.qname = source.qname
                attr_type.reference = source.ref
                attr_type.forward = False

    @classmethod
    def find_forward_attr(cls, target: Class, qname: str) -> Optional[Attr]:
        """Find the first attr that references the given inner class qname.

        Args:
            target: The target class instance
            qname: An inner class qualified name

        Returns:
            Attr: The first attr that references the given qname
            None: If no such attr exists, it can happen!
        """
        for attr in target.attrs:
            for attr_type in attr.types:
                if attr_type.forward and attr_type.qname == qname:
                    return attr

        return None

process(target)

Process entrypoint for classes.

Process the target class inner classes recursively.

All enumerations are promoted by default, otherwise only if the configuration is disabled the classes are ignored.

Parameters:

Name Type Description Default
target Class

The target class instance to inspect

required
Source code in xsdata/codegen/handlers/unnest_inner_classes.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def process(self, target: Class):
    """Process entrypoint for classes.

    Process the target class inner classes recursively.

    All enumerations are promoted by default, otherwise
    only if the configuration is disabled the classes
    are ignored.

    Args:
        target: The target class instance to inspect
    """
    for inner in list(target.inner):
        if inner.is_enumeration or self.container.config.output.unnest_classes:
            self.promote(target, inner)

promote(target, inner)

Promote the inner class to root classes.

Steps
  • Replace forward references to the inner class
  • Remove inner class from target class
  • Copy the class to the global class container.

Parameters:

Name Type Description Default
target Class

The target class

required
inner Class

An inner class

required
Source code in xsdata/codegen/handlers/unnest_inner_classes.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def promote(self, target: Class, inner: Class):
    """Promote the inner class to root classes.

    Steps:
        - Replace forward references to the inner class
        - Remove inner class from target class
        - Copy the class to the global class container.

    Args:
        target: The target class
        inner: An inner class
    """
    target.inner.remove(inner)
    attr = self.find_forward_attr(target, inner.qname)
    if attr:
        clone = self.clone_class(inner, target.name)
        self.update_types(attr, inner.qname, clone)
        self.container.add(clone)

clone_class(inner, name) classmethod

Clone and prepare inner class for promotion.

Clone the inner class, mark it as promoted and pref the qualified name with the parent class name.

Parameters:

Name Type Description Default
inner Class

The inner class to clone and prepare

required
name str

The parent class name to use a prefix

required

Returns:

Type Description
Class

The new class instance

Source code in xsdata/codegen/handlers/unnest_inner_classes.py
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
@classmethod
def clone_class(cls, inner: Class, name: str) -> Class:
    """Clone and prepare inner class for promotion.

    Clone the inner class, mark it as promoted and pref
    the qualified name with the parent class name.

    Args:
        inner: The inner class to clone and prepare
        name: The parent class name to use a prefix

    Returns:
        The new class instance
    """
    clone = inner.clone()
    clone.parent = None
    clone.local_type = True
    clone.qname = build_qname(inner.target_namespace, f"{name}_{inner.name}")

    for attr in clone.attrs:
        for tp in attr.types:
            if tp.circular and tp.qname == inner.qname:
                tp.qname = clone.qname
                tp.reference = clone.ref

    return clone

update_types(attr, search, source) classmethod

Update the references from an inner to a global class.

Parameters:

Name Type Description Default
attr Attr

The target attr to inspect and update

required
search str

The current inner class qname

required
source Class

The new global class qname

required
Source code in xsdata/codegen/handlers/unnest_inner_classes.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
@classmethod
def update_types(cls, attr: Attr, search: str, source: Class):
    """Update the references from an inner to a global class.

    Args:
        attr: The target attr to inspect and update
        search: The current inner class qname
        source: The new global class qname
    """
    for attr_type in attr.types:
        if attr_type.qname == search and attr_type.forward:
            attr_type.qname = source.qname
            attr_type.reference = source.ref
            attr_type.forward = False

find_forward_attr(target, qname) classmethod

Find the first attr that references the given inner class qname.

Parameters:

Name Type Description Default
target Class

The target class instance

required
qname str

An inner class qualified name

required

Returns:

Name Type Description
Attr Optional[Attr]

The first attr that references the given qname

None Optional[Attr]

If no such attr exists, it can happen!

Source code in xsdata/codegen/handlers/unnest_inner_classes.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
@classmethod
def find_forward_attr(cls, target: Class, qname: str) -> Optional[Attr]:
    """Find the first attr that references the given inner class qname.

    Args:
        target: The target class instance
        qname: An inner class qualified name

    Returns:
        Attr: The first attr that references the given qname
        None: If no such attr exists, it can happen!
    """
    for attr in target.attrs:
        for attr_type in attr.types:
            if attr_type.forward and attr_type.qname == qname:
                return attr

    return None