Skip to content

# vacuum_inner_classes

## `xsdata.codegen.handlers.vacuum_inner_classes`

### `VacuumInnerClasses`

Bases: `HandlerInterface`

Cleanup nested classes.

Search and vacuum inner classes with no attributes or a single extension or rename inner classes that have the same name as the outer/parent class.

Cases

1. Filter duplicate inner classes
2. Removing identical overriding fields can sometimes leave a class bare with just an extension. For inner classes we can safely replace the forward reference with the inner extension reference.
3. Empty nested complexContent with no restrictions or extensions, we can replace these references with xs:anySimpleType

Source code in `xsdata/codegen/handlers/vacuum_inner_classes.py`

    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

    class VacuumInnerClasses(HandlerInterface):
        """Cleanup nested classes.

        Search and vacuum inner classes with no attributes or a single extension or
        rename inner classes that have the same name as the outer/parent class.

        Cases:
            1. Filter duplicate inner classes
            2. Removing identical overriding fields can sometimes leave a class
               bare with just an extension. For inner classes we can safely
               replace the forward reference with the inner extension reference.
            3. Empty nested complexContent with no restrictions or extensions,
               we can replace these references with xs:anySimpleType
        """

        __slots__ = ()

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

            Args:
                target: The target class instance
            """
            target.inner = collections.unique_sequence(target.inner, key="qname")
            for inner in target.inner.copy():
                if not inner.attrs and len(inner.extensions) < 2:
                    self.remove_inner(target, inner)
                elif inner.qname == target.qname:
                    self.rename_inner(target, inner)

        @classmethod
        def remove_inner(cls, target: Class, inner: Class):
            """Remove inner class and update the target class attrs.

            Args:
                target: The target class instance
                inner: The nested class instance
            """
            target.inner.remove(inner)

            for attr_type in cls.find_attr_types(target, inner.qname):
                attr_type.circular = False
                attr_type.forward = False

                if inner.extensions:
                    ext = inner.extensions[0]
                    attr_type.reference = ext.type.reference
                    attr_type.qname = ext.type.qname
                    attr_type.native = False
                else:
                    attr_type.native = True
                    attr_type.qname = str(DataType.ANY_SIMPLE_TYPE)
                    attr_type.reference = 0

        @classmethod
        def rename_inner(cls, target: Class, inner: Class):
            """Rename the inner class and update the target class attrs.

            The inner class will get the `Inner suffix`.

            Args:
                target: The target class instance
                inner: The nested class instance
            """
            namespace = inner.target_namespace
            old_qname = inner.qname
            inner.qname = build_qname(namespace, f"{inner.name}_Inner")

            for attr_type in cls.find_attr_types(target, old_qname):
                attr_type.qname = inner.qname

        @classmethod
        def find_attr_types(cls, target: Class, qname: str) -> Iterator[AttrType]:
            """Find attr and choice types by the qualified name.

            Args:
                target: The target class instance
                qname: The qualified name
            """
            for attr in target.attrs:
                for attr_type in attr.types:
                    if attr_type.forward and attr_type.qname == qname:
                        yield attr_type

                for choice in attr.choices:
                    for choice_type in choice.types:
                        if choice_type.forward and choice_type.qname == qname:
                            yield choice_type

#### `process(target)`

Process entrypoint for classes.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`target` | `Class` | The target class instance | required

Source code in `xsdata/codegen/handlers/vacuum_inner_classes.py`

    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38

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

        Args:
            target: The target class instance
        """
        target.inner = collections.unique_sequence(target.inner, key="qname")
        for inner in target.inner.copy():
            if not inner.attrs and len(inner.extensions) < 2:
                self.remove_inner(target, inner)
            elif inner.qname == target.qname:
                self.rename_inner(target, inner)

#### `remove_inner(target, inner)` `classmethod`

Remove inner class and update the target class attrs.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`target` | `Class` | The target class instance | required
`inner` | `Class` | The nested class instance | required

Source code in `xsdata/codegen/handlers/vacuum_inner_classes.py`

    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62

    @classmethod
    def remove_inner(cls, target: Class, inner: Class):
        """Remove inner class and update the target class attrs.

        Args:
            target: The target class instance
            inner: The nested class instance
        """
        target.inner.remove(inner)

        for attr_type in cls.find_attr_types(target, inner.qname):
            attr_type.circular = False
            attr_type.forward = False

            if inner.extensions:
                ext = inner.extensions[0]
                attr_type.reference = ext.type.reference
                attr_type.qname = ext.type.qname
                attr_type.native = False
            else:
                attr_type.native = True
                attr_type.qname = str(DataType.ANY_SIMPLE_TYPE)
                attr_type.reference = 0

#### `rename_inner(target, inner)` `classmethod`

Rename the inner class and update the target class attrs.

The inner class will get the `Inner suffix`.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`target` | `Class` | The target class instance | required
`inner` | `Class` | The nested class instance | required

Source code in `xsdata/codegen/handlers/vacuum_inner_classes.py`

    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79

    @classmethod
    def rename_inner(cls, target: Class, inner: Class):
        """Rename the inner class and update the target class attrs.

        The inner class will get the `Inner suffix`.

        Args:
            target: The target class instance
            inner: The nested class instance
        """
        namespace = inner.target_namespace
        old_qname = inner.qname
        inner.qname = build_qname(namespace, f"{inner.name}_Inner")

        for attr_type in cls.find_attr_types(target, old_qname):
            attr_type.qname = inner.qname

#### `find_attr_types(target, qname)` `classmethod`

Find attr and choice types by the qualified name.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`target` | `Class` | The target class instance | required
`qname` | `str` | The qualified name | required

Source code in `xsdata/codegen/handlers/vacuum_inner_classes.py`

    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97

    @classmethod
    def find_attr_types(cls, target: Class, qname: str) -> Iterator[AttrType]:
        """Find attr and choice types by the qualified name.

        Args:
            target: The target class instance
            qname: The qualified name
        """
        for attr in target.attrs:
            for attr_type in attr.types:
                if attr_type.forward and attr_type.qname == qname:
                    yield attr_type

            for choice in attr.choices:
                for choice_type in choice.types:
                    if choice_type.forward and choice_type.qname == qname:
                        yield choice_type