Skip to content

models

xsdata.codegen.models

CodegenModel dataclass

Base codegen model.

Source code in xsdata/codegen/models.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@dataclass
class CodegenModel:
    """Base codegen model."""

    def clone(self: T, **kwargs: Any) -> T:
        """Return a deep cloned instance."""
        clone = copy.deepcopy(self)
        return replace(clone, **kwargs) if kwargs else clone

    def swap(self, source: "CodegenModel"):
        """Swap the instance attributes from the source instance."""
        for f in fields(self):
            value = copy.deepcopy(getattr(source, f.name))
            setattr(self, f.name, value)

clone(**kwargs)

Return a deep cloned instance.

Source code in xsdata/codegen/models.py
39
40
41
42
def clone(self: T, **kwargs: Any) -> T:
    """Return a deep cloned instance."""
    clone = copy.deepcopy(self)
    return replace(clone, **kwargs) if kwargs else clone

swap(source)

Swap the instance attributes from the source instance.

Source code in xsdata/codegen/models.py
44
45
46
47
48
def swap(self, source: "CodegenModel"):
    """Swap the instance attributes from the source instance."""
    for f in fields(self):
        value = copy.deepcopy(getattr(source, f.name))
        setattr(self, f.name, value)

Restrictions dataclass

Bases: CodegenModel

Class field validation restrictions.

Parameters:

Name Type Description Default
min_occurs Optional[int]

The minimum number of occurrences

None
max_occurs Optional[int]

The maximum number of occurrences

None
min_exclusive Optional[str]

The lower exclusive bound for numeric values

None
min_inclusive Optional[str]

The lower inclusive bound for numeric values

None
min_length Optional[int]

The minimum length of characters or list items allowed

None
max_exclusive Optional[str]

The upper exclusive bound for numeric values

None
max_inclusive Optional[str]

The upper inclusive bound for numeric values

None
max_length Optional[int]

The max length of characters or list items allowed

None
total_digits Optional[int]

The exact number of digits allowed for numeric values

None
fraction_digits Optional[int]

The maximum number of decimal places allowed

None
length Optional[int]

The exact number of characters or list items allowed

None
white_space Optional[str]

Specifies how white space is handled

None
pattern Optional[str]

Defines the exact sequence of characters that are acceptable

None
explicit_timezone Optional[str]

Require or prohibit the time zone offset in date/time

None
nillable Optional[bool]

Specifies whether nil content is allowed

None
sequence Optional[int]

The sequence reference number of the attr

None
tokens Optional[bool]

Specifies whether the value needs tokenization

None
format Optional[str]

The output format used for byte and datetime types

None
choice Optional[int]

The choice reference number of the attr

None
group Optional[int]

The group reference number of the attr

None
process_contents Optional[str]

Specifies the content processed mode: strict, lax, skip

None
path List[Tuple[str, int, int, int]]

The coded attr path in the source document

list()
Source code in xsdata/codegen/models.py
 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
@dataclass
class Restrictions(CodegenModel):
    """Class field validation restrictions.

    Args:
        min_occurs: The minimum number of occurrences
        max_occurs: The maximum number of occurrences
        min_exclusive: The lower exclusive bound for numeric values
        min_inclusive: The lower inclusive bound for numeric values
        min_length: The minimum length of characters or list items allowed
        max_exclusive: The upper exclusive bound for numeric values
        max_inclusive: The upper inclusive bound for numeric values
        max_length: The max length of characters or list items allowed
        total_digits:  The exact number of digits allowed for numeric values
        fraction_digits: The maximum number of decimal places allowed
        length: The exact number of characters or list items allowed
        white_space: Specifies how white space is handled
        pattern: Defines the exact sequence of characters that are acceptable
        explicit_timezone: Require or prohibit the time zone offset in date/time
        nillable: Specifies whether nil content is allowed
        sequence: The sequence reference number of the attr
        tokens: Specifies whether the value needs tokenization
        format: The output format used for byte and datetime types
        choice: The choice reference number of the attr
        group: The group reference number of the attr
        process_contents: Specifies the content processed mode: strict, lax, skip
        path: The coded attr path in the source document
    """

    min_occurs: Optional[int] = field(default=None)
    max_occurs: Optional[int] = field(default=None)
    min_exclusive: Optional[str] = field(default=None)
    min_inclusive: Optional[str] = field(default=None)
    min_length: Optional[int] = field(default=None)
    max_exclusive: Optional[str] = field(default=None)
    max_inclusive: Optional[str] = field(default=None)
    max_length: Optional[int] = field(default=None)
    total_digits: Optional[int] = field(default=None)
    fraction_digits: Optional[int] = field(default=None)
    length: Optional[int] = field(default=None)
    white_space: Optional[str] = field(default=None)
    pattern: Optional[str] = field(default=None)
    explicit_timezone: Optional[str] = field(default=None)
    nillable: Optional[bool] = field(default=None)
    sequence: Optional[int] = field(default=None, compare=False)
    tokens: Optional[bool] = field(default=None)
    format: Optional[str] = field(default=None)
    choice: Optional[int] = field(default=None, compare=False)
    group: Optional[int] = field(default=None)
    process_contents: Optional[str] = field(default=None)
    path: List[Tuple[str, int, int, int]] = field(default_factory=list)

    @property
    def is_list(self) -> bool:
        """Return whether the max occurs larger than one."""
        return self.max_occurs is not None and self.max_occurs > 1

    @property
    def is_optional(self) -> bool:
        """Return whether the min occurs is zero."""
        return self.min_occurs == 0

    @property
    def is_prohibited(self) -> bool:
        """Return whether the max occurs is zero."""
        return self.max_occurs == 0

    def merge(self, source: "Restrictions"):
        """Update properties from another instance.

        Args:
            source: The source instance to merge properties from
        """
        keys = (
            "min_exclusive",
            "min_inclusive",
            "min_length",
            "max_exclusive",
            "max_inclusive",
            "max_length",
            "total_digits",
            "fraction_digits",
            "length",
            "white_space",
            "pattern",
            "explicit_timezone",
            "process_contents",
        )

        for key in keys:
            value = getattr(source, key)
            if value is not None:
                setattr(self, key, value)

        self.path = source.path + self.path
        self.sequence = self.sequence or source.sequence
        self.choice = self.choice or source.choice
        self.tokens = self.tokens or source.tokens
        self.format = self.format or source.format
        self.group = self.group or source.group

        if self.min_occurs is None and source.min_occurs is not None:
            self.min_occurs = source.min_occurs

        if self.max_occurs is None and source.max_occurs is not None:
            self.max_occurs = source.max_occurs

    def asdict(self, types: Optional[List[Type]] = None) -> Dict:
        """Return the initialized only properties as a dictionary.

        Skip None or implied values, and optionally use the
        attribute types to convert relevant options.

        Args:
            types: An optional list of attr python types

        Returns:
            A key-value of map of the attr restrictions for generation.
        """
        result = {}
        sorted_types = converter.sort_types(types) if types else []

        if self.is_list:
            if self.min_occurs is not None and self.min_occurs > 0:
                result["min_occurs"] = self.min_occurs
            if self.max_occurs is not None and self.max_occurs < sys.maxsize:
                result["max_occurs"] = self.max_occurs
        elif (
            self.min_occurs == self.max_occurs == 1
            and not self.nillable
            and not self.tokens
        ):
            result["required"] = True

        for key, value in asdict(self).items():
            if value is None or key in (
                "choice",
                "group",
                "min_occurs",
                "max_occurs",
                "path",
            ):
                continue

            if key == "process_contents" and value != "skip":
                continue

            if key.endswith("clusive") and types:
                value = converter.deserialize(value, sorted_types)

            result[key] = value

        return result

    @classmethod
    def from_element(cls, element: ElementBase) -> "Restrictions":
        """Static constructor from a xsd model.

        Args:
            element: A element base instance.

        Returns:
            The new restrictions instance
        """
        return cls(**element.get_restrictions())

is_list: bool property

Return whether the max occurs larger than one.

is_optional: bool property

Return whether the min occurs is zero.

is_prohibited: bool property

Return whether the max occurs is zero.

merge(source)

Update properties from another instance.

Parameters:

Name Type Description Default
source Restrictions

The source instance to merge properties from

required
Source code in xsdata/codegen/models.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
def merge(self, source: "Restrictions"):
    """Update properties from another instance.

    Args:
        source: The source instance to merge properties from
    """
    keys = (
        "min_exclusive",
        "min_inclusive",
        "min_length",
        "max_exclusive",
        "max_inclusive",
        "max_length",
        "total_digits",
        "fraction_digits",
        "length",
        "white_space",
        "pattern",
        "explicit_timezone",
        "process_contents",
    )

    for key in keys:
        value = getattr(source, key)
        if value is not None:
            setattr(self, key, value)

    self.path = source.path + self.path
    self.sequence = self.sequence or source.sequence
    self.choice = self.choice or source.choice
    self.tokens = self.tokens or source.tokens
    self.format = self.format or source.format
    self.group = self.group or source.group

    if self.min_occurs is None and source.min_occurs is not None:
        self.min_occurs = source.min_occurs

    if self.max_occurs is None and source.max_occurs is not None:
        self.max_occurs = source.max_occurs

asdict(types=None)

Return the initialized only properties as a dictionary.

Skip None or implied values, and optionally use the attribute types to convert relevant options.

Parameters:

Name Type Description Default
types Optional[List[Type]]

An optional list of attr python types

None

Returns:

Type Description
Dict

A key-value of map of the attr restrictions for generation.

Source code in xsdata/codegen/models.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
def asdict(self, types: Optional[List[Type]] = None) -> Dict:
    """Return the initialized only properties as a dictionary.

    Skip None or implied values, and optionally use the
    attribute types to convert relevant options.

    Args:
        types: An optional list of attr python types

    Returns:
        A key-value of map of the attr restrictions for generation.
    """
    result = {}
    sorted_types = converter.sort_types(types) if types else []

    if self.is_list:
        if self.min_occurs is not None and self.min_occurs > 0:
            result["min_occurs"] = self.min_occurs
        if self.max_occurs is not None and self.max_occurs < sys.maxsize:
            result["max_occurs"] = self.max_occurs
    elif (
        self.min_occurs == self.max_occurs == 1
        and not self.nillable
        and not self.tokens
    ):
        result["required"] = True

    for key, value in asdict(self).items():
        if value is None or key in (
            "choice",
            "group",
            "min_occurs",
            "max_occurs",
            "path",
        ):
            continue

        if key == "process_contents" and value != "skip":
            continue

        if key.endswith("clusive") and types:
            value = converter.deserialize(value, sorted_types)

        result[key] = value

    return result

from_element(element) classmethod

Static constructor from a xsd model.

Parameters:

Name Type Description Default
element ElementBase

A element base instance.

required

Returns:

Type Description
Restrictions

The new restrictions instance

Source code in xsdata/codegen/models.py
205
206
207
208
209
210
211
212
213
214
215
@classmethod
def from_element(cls, element: ElementBase) -> "Restrictions":
    """Static constructor from a xsd model.

    Args:
        element: A element base instance.

    Returns:
        The new restrictions instance
    """
    return cls(**element.get_restrictions())

AttrType dataclass

Bases: CodegenModel

Class field typing information.

Parameters:

Name Type Description Default
qname str

The namespace qualified name

required
alias Optional[str]

The type alias

None
reference int

The type reference number

0
native bool

Specifies if it's python native type

False
forward bool

Specifies if it's a forward reference

False
circular bool

Specifies if it's a circular reference

False
substituted bool

Specifies if it has been processed for substitution groups

False
Source code in xsdata/codegen/models.py
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
@dataclass(unsafe_hash=True)
class AttrType(CodegenModel):
    """Class field typing information.

    Args:
        qname: The namespace qualified name
        alias: The type alias
        reference: The type reference number
        native: Specifies if it's python native type
        forward: Specifies if it's a forward reference
        circular: Specifies if it's a circular reference
        substituted: Specifies if it has been processed for substitution groups
    """

    qname: str
    alias: Optional[str] = field(default=None, compare=False)
    reference: int = field(default=0, compare=False)
    native: bool = field(default=False)
    forward: bool = field(default=False)
    circular: bool = field(default=False)
    substituted: bool = field(default=False, compare=False)

    @property
    def datatype(self) -> Optional[DataType]:
        """Return the datatype instance if native, none otherwise."""
        return DataType.from_qname(self.qname) if self.native else None

    @property
    def name(self) -> str:
        """Shortcut for qname local name."""
        return namespaces.local_name(self.qname)

    def is_dependency(self, allow_circular: bool) -> bool:
        """Return whether this type is a dependency.

        The type must a reference to a user type, not a forward
        reference and not a circular unless if it's allowed.

        Args:
            allow_circular: Allow circular references as dependencies

        Returns:
            The bool result/
        """
        return not (
            self.forward or self.native or (not allow_circular and self.circular)
        )

datatype: Optional[DataType] property

Return the datatype instance if native, none otherwise.

name: str property

Shortcut for qname local name.

is_dependency(allow_circular)

Return whether this type is a dependency.

The type must a reference to a user type, not a forward reference and not a circular unless if it's allowed.

Parameters:

Name Type Description Default
allow_circular bool

Allow circular references as dependencies

required

Returns:

Type Description
bool

The bool result/

Source code in xsdata/codegen/models.py
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
def is_dependency(self, allow_circular: bool) -> bool:
    """Return whether this type is a dependency.

    The type must a reference to a user type, not a forward
    reference and not a circular unless if it's allowed.

    Args:
        allow_circular: Allow circular references as dependencies

    Returns:
        The bool result/
    """
    return not (
        self.forward or self.native or (not allow_circular and self.circular)
    )

Attr dataclass

Bases: CodegenModel

Class field model representation.

Parameters:

Name Type Description Default
tag str

The xml tag that produced this attr

required
name str

The final attr name

required
local_name str

The original attr name

''
wrapper Optional[str]

The wrapper element name

None
index int

The index position of this attr in the class

int()
default Optional[str]

The default value

None
fixed bool

Specifies if the default value is fixed

False
mixed bool

Specifies if the attr supports mixed content

False
types List[AttrType]

The attr types list

list()
choices List[Attr]

The attr choice list

list()
namespace Optional[str]

The attr namespace

None
help Optional[str]

The attr help text

None
restrictions Restrictions

The attr restrictions instance

Restrictions()
parent Optional[str]

The parent class qualified name of the attr

None
substitution Optional[str]

The substitution group this attr belongs to

None
Source code in xsdata/codegen/models.py
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
@dataclass
class Attr(CodegenModel):
    """Class field model representation.

    Args:
        tag: The xml tag that produced this attr
        name: The final attr name
        local_name: The original attr name
        wrapper: The wrapper element name
        index: The index position of this attr in the class
        default: The default value
        fixed: Specifies if the default value is fixed
        mixed: Specifies if the attr supports mixed content
        types: The attr types list
        choices: The attr choice list
        namespace: The attr namespace
        help: The attr help text
        restrictions: The attr restrictions instance
        parent: The parent class qualified name of the attr
        substitution: The substitution group this attr belongs to
    """

    tag: str
    name: str = field(compare=False)
    local_name: str = field(default="")
    wrapper: Optional[str] = field(default=None)
    index: int = field(compare=False, default_factory=int)
    default: Optional[str] = field(default=None, compare=False)
    fixed: bool = field(default=False, compare=False)
    mixed: bool = field(default=False, compare=False)
    types: List[AttrType] = field(default_factory=list, compare=False)
    choices: List["Attr"] = field(default_factory=list, compare=False)
    namespace: Optional[str] = field(default=None)
    help: Optional[str] = field(default=None, compare=False)
    restrictions: Restrictions = field(default_factory=Restrictions, compare=False)
    parent: Optional[str] = field(default=None, compare=False)
    substitution: Optional[str] = field(default=None, compare=False)

    def __post_init__(self):
        """Post init processing."""
        if not self.local_name:
            self.local_name = self.name

        if text.alnum(self.name) == "":
            self.name = "_".join(unicodedata.name(char) for char in self.name)

    @property
    def key(self) -> str:
        """Generate a key for this attr.

        Concatenate the tag/namespace/local_name.
        This key is used to find duplicates, it's not
        supposed to be unique.

        Returns:
            The unique key for this attr.

        """
        return f"{self.tag}.{self.namespace}.{self.local_name}"

    @property
    def qname(self) -> str:
        """Return the fully qualified name of the attr."""
        return namespaces.build_qname(self.namespace, self.local_name)

    @property
    def is_attribute(self) -> bool:
        """Return whether this attr represents a xml attribute node."""
        return self.tag in (Tag.ATTRIBUTE, Tag.ANY_ATTRIBUTE)

    @property
    def is_element(self) -> bool:
        """Return whether this attr represents a xml element."""
        return self.tag == Tag.ELEMENT

    @property
    def is_enumeration(self) -> bool:
        """Return whether this attr an enumeration member."""
        return self.tag == Tag.ENUMERATION

    @property
    def is_dict(self) -> bool:
        """Return whether this attr is derived from xs:anyAttribute."""
        return self.tag == Tag.ANY_ATTRIBUTE

    @property
    def is_factory(self) -> bool:
        """Return whether this attribute is a list of items or a mapping."""
        return self.is_list or self.is_dict or self.is_tokens

    @property
    def is_forward_ref(self) -> bool:
        """Return whether any attr types is a forward or circular reference."""
        return any(tp.circular or tp.forward for tp in self.types)

    @property
    def is_circular_ref(self) -> bool:
        """Return whether any attr types is a circular reference."""
        return any(tp.circular for tp in self.types)

    @property
    def is_group(self) -> bool:
        """Return whether this attr is a reference to a group class."""
        return self.tag in (Tag.ATTRIBUTE_GROUP, Tag.GROUP)

    @property
    def is_list(self) -> bool:
        """Return whether this attr requires a list of values."""
        return self.restrictions.is_list

    @property
    def is_prohibited(self) -> bool:
        """Return whether this attr is prohibited."""
        return self.restrictions.is_prohibited

    @property
    def is_nameless(self) -> bool:
        """Return whether this attr is a real xml node."""
        return self.tag not in (Tag.ATTRIBUTE, Tag.ELEMENT)

    @property
    def is_nillable(self) -> bool:
        """Return whether this attr supports nil values."""
        return self.restrictions.nillable is True

    @property
    def is_optional(self) -> bool:
        """Return whether this attr is not required."""
        return self.restrictions.is_optional

    @property
    def is_suffix(self) -> bool:
        """Return whether this attr is supposed to be generated last."""
        return self.index == sys.maxsize

    @property
    def is_xsi_type(self) -> bool:
        """Return whether this attr represents a xsi:type attribute."""
        return self.namespace == Namespace.XSI.uri and self.name == "type"

    @property
    def is_tokens(self) -> bool:
        """Return whether this attr supports token values."""
        return self.restrictions.tokens is True

    @property
    def is_wildcard(self) -> bool:
        """Return whether this attr supports any content."""
        return self.tag in (Tag.ANY_ATTRIBUTE, Tag.ANY)

    @property
    def is_any_type(self) -> bool:
        """Return whether this attr types support any content."""
        return any(tp is object for tp in self.get_native_types())

    @property
    def native_types(self) -> List[Type]:
        """Return a list of all the builtin data types."""
        return list(set(self.get_native_types()))

    @property
    def user_types(self) -> Iterator[AttrType]:
        """Yield an iterator of all the user defined types."""
        for tp in self.types:
            if not tp.native:
                yield tp

    @property
    def slug(self) -> str:
        """Return the slugified name of the attr."""
        return text.alnum(self.name)

    @property
    def xml_type(self) -> Optional[str]:
        """Return the xml type this attribute is mapped to."""
        return xml_type_map.get(self.tag)

    def get_native_types(self) -> Iterator[Type]:
        """Yield an iterator of all the native attr types."""
        for tp in self.types:
            datatype = tp.datatype
            if datatype:
                yield datatype.type

    def can_be_restricted(self) -> bool:
        """Return whether this attr can be restricted."""
        return self.xml_type not in (Tag.ATTRIBUTE, None)

key: str property

Generate a key for this attr.

Concatenate the tag/namespace/local_name. This key is used to find duplicates, it's not supposed to be unique.

Returns:

Type Description
str

The unique key for this attr.

qname: str property

Return the fully qualified name of the attr.

is_attribute: bool property

Return whether this attr represents a xml attribute node.

is_element: bool property

Return whether this attr represents a xml element.

is_enumeration: bool property

Return whether this attr an enumeration member.

is_dict: bool property

Return whether this attr is derived from xs:anyAttribute.

is_factory: bool property

Return whether this attribute is a list of items or a mapping.

is_forward_ref: bool property

Return whether any attr types is a forward or circular reference.

is_circular_ref: bool property

Return whether any attr types is a circular reference.

is_group: bool property

Return whether this attr is a reference to a group class.

is_list: bool property

Return whether this attr requires a list of values.

is_prohibited: bool property

Return whether this attr is prohibited.

is_nameless: bool property

Return whether this attr is a real xml node.

is_nillable: bool property

Return whether this attr supports nil values.

is_optional: bool property

Return whether this attr is not required.

is_suffix: bool property

Return whether this attr is supposed to be generated last.

is_xsi_type: bool property

Return whether this attr represents a xsi:type attribute.

is_tokens: bool property

Return whether this attr supports token values.

is_wildcard: bool property

Return whether this attr supports any content.

is_any_type: bool property

Return whether this attr types support any content.

native_types: List[Type] property

Return a list of all the builtin data types.

user_types: Iterator[AttrType] property

Yield an iterator of all the user defined types.

slug: str property

Return the slugified name of the attr.

xml_type: Optional[str] property

Return the xml type this attribute is mapped to.

__post_init__()

Post init processing.

Source code in xsdata/codegen/models.py
305
306
307
308
309
310
311
def __post_init__(self):
    """Post init processing."""
    if not self.local_name:
        self.local_name = self.name

    if text.alnum(self.name) == "":
        self.name = "_".join(unicodedata.name(char) for char in self.name)

get_native_types()

Yield an iterator of all the native attr types.

Source code in xsdata/codegen/models.py
444
445
446
447
448
449
def get_native_types(self) -> Iterator[Type]:
    """Yield an iterator of all the native attr types."""
    for tp in self.types:
        datatype = tp.datatype
        if datatype:
            yield datatype.type

can_be_restricted()

Return whether this attr can be restricted.

Source code in xsdata/codegen/models.py
451
452
453
def can_be_restricted(self) -> bool:
    """Return whether this attr can be restricted."""
    return self.xml_type not in (Tag.ATTRIBUTE, None)

Extension dataclass

Bases: CodegenModel

Base class model representation.

Parameters:

Name Type Description Default
tag str

The xml tag that produced this extension

required
type AttrType

The extension type

required
restrictions Restrictions

The extension restrictions instance

required
Source code in xsdata/codegen/models.py
456
457
458
459
460
461
462
463
464
465
466
467
468
@dataclass(unsafe_hash=True)
class Extension(CodegenModel):
    """Base class model representation.

    Args:
        tag: The xml tag that produced this extension
        type: The extension type
        restrictions: The extension restrictions instance
    """

    tag: str
    type: AttrType
    restrictions: Restrictions = field(hash=False)

Status

Bases: IntEnum

Class process status enumeration.

Source code in xsdata/codegen/models.py
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
class Status(IntEnum):
    """Class process status enumeration."""

    RAW = 0
    UNGROUPING = 10
    UNGROUPED = 11
    FLATTENING = 20
    FLATTENED = 21
    SANITIZING = 30
    SANITIZED = 31
    RESOLVING = 40
    RESOLVED = 41
    CLEANING = 50
    CLEANED = 51
    FINALIZING = 60
    FINALIZED = 61

Class dataclass

Bases: CodegenModel

Class model representation.

Parameters:

Name Type Description Default
qname str

The namespace qualified name

required
tag str

The xml tag that produced this class

required
location str

The schema/document location uri

required
mixed bool

Specifies whether this class supports mixed content

False
abstract bool

Specifies whether this is an abstract class

False
nillable bool

Specifies whether this class supports nil content

False
local_type bool

Specifies if this class was an inner type at some point

False
status Status

The processing status of the class

RAW
container Optional[str]

The xml container of the class, schema, override, redefine

None
package Optional[str]

The designated package of the class

None
module Optional[str]

The designated module of the class

None
namespace Optional[str]

The class namespace

None
help Optional[str]

The help text

None
meta_name Optional[str]

The xml element name of the class

None
default Any

The default value

None
fixed bool

Specifies whether the default value is fixed

False
substitutions List[str]

The list of all the substitution groups this class belongs to

list()
extensions List[Extension]

The list of all the extension instances

list()
attrs List[Attr]

The list of all the attr instances

list()
inner List[Class]

The list of all the inner class instances

list()
ns_map Dict

The namespace prefix-URI map

dict()
parent Optional[Class]

The parent outer class

None
Source code in xsdata/codegen/models.py
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
@dataclass
class Class(CodegenModel):
    """Class model representation.

    Args:
        qname: The namespace qualified name
        tag: The xml tag that produced this class
        location: The schema/document location uri
        mixed: Specifies whether this class supports mixed content
        abstract: Specifies whether this is an abstract class
        nillable: Specifies whether this class supports nil content
        local_type: Specifies if this class was an inner type at some point
        status: The processing status of the class
        container: The xml container of the class, schema, override, redefine
        package: The designated package of the class
        module: The designated module of the class
        namespace: The class namespace
        help: The help text
        meta_name: The xml element name of the class
        default: The default value
        fixed: Specifies whether the default value is fixed
        substitutions: The list of all the substitution groups this class belongs to
        extensions: The list of all the extension instances
        attrs: The list of all the attr instances
        inner: The list of all the inner class instances
        ns_map: The namespace prefix-URI map
        parent: The parent outer class
    """

    qname: str
    tag: str
    location: str = field(compare=False)
    mixed: bool = field(default=False)
    abstract: bool = field(default=False)
    nillable: bool = field(default=False)
    local_type: bool = field(default=False)
    status: Status = field(default=Status.RAW)
    container: Optional[str] = field(default=None)
    package: Optional[str] = field(default=None)
    module: Optional[str] = field(default=None)
    namespace: Optional[str] = field(default=None)
    help: Optional[str] = field(default=None)
    meta_name: Optional[str] = field(default=None)
    default: Any = field(default=None, compare=False)
    fixed: bool = field(default=False, compare=False)
    substitutions: List[str] = field(default_factory=list)
    extensions: List[Extension] = field(default_factory=list)
    attrs: List[Attr] = field(default_factory=list)
    inner: List["Class"] = field(default_factory=list)
    ns_map: Dict = field(default_factory=dict)
    parent: Optional["Class"] = field(default=None, compare=False)

    @property
    def name(self) -> str:
        """Shortcut for the class local name."""
        return namespaces.local_name(self.qname)

    @property
    def slug(self) -> str:
        """Return a slugified version of the class name."""
        return text.alnum(self.name)

    @property
    def ref(self) -> int:
        """Return this id reference of this instance."""
        return id(self)

    @property
    def target_namespace(self) -> Optional[str]:
        """Return the class target namespace."""
        return namespaces.target_uri(self.qname)

    @property
    def has_suffix_attr(self) -> bool:
        """Return whether it includes a suffix attr."""
        return any(attr.is_suffix for attr in self.attrs)

    @property
    def has_help_attr(self) -> bool:
        """Return whether at least one of attrs has help content."""
        return any(attr.help and attr.help.strip() for attr in self.attrs)

    @property
    def is_element(self) -> bool:
        """Return whether this class represents a xml element."""
        return self.tag == Tag.ELEMENT

    @property
    def is_enumeration(self) -> bool:
        """Return whether all attrs are enumeration members."""
        return len(self.attrs) > 0 and all(attr.is_enumeration for attr in self.attrs)

    @property
    def is_complex_type(self) -> bool:
        """Return whether this class represents a root/global class.

        Global classes are the only classes that get generated by default.
        """
        return self.tag in GLOBAL_TYPES

    @property
    def is_group(self) -> bool:
        """Return whether this class is derived from a xs:group/attributeGroup."""
        return self.tag in (Tag.ATTRIBUTE_GROUP, Tag.GROUP)

    @property
    def is_nillable(self) -> bool:
        """Return whether this class represents a nillable xml element."""
        return self.nillable or any(x.restrictions.nillable for x in self.extensions)

    @property
    def is_mixed(self) -> bool:
        """Return whether this class supports mixed content."""
        return self.mixed or any(x.mixed for x in self.attrs)

    @property
    def is_restricted(self) -> bool:
        """Return whether this class includes any restriction extensions."""
        return any(
            True for extension in self.extensions if extension.tag == Tag.RESTRICTION
        )

    @property
    def is_service(self) -> bool:
        """Return whether this instance is derived from a wsdl:operation."""
        return self.tag == Tag.BINDING_OPERATION

    @property
    def references(self) -> Iterator[int]:
        """Yield all class object reference numbers."""
        for tp in self.types():
            if tp.reference:
                yield tp.reference

    @property
    def target_module(self) -> str:
        """Return the designated full module path.

        Raises:
            CodeGenerationError: if the target was not designated
                a package and module.
        """
        if self.package and self.module:
            return f"{self.package}.{self.module}"

        if self.module:
            return self.module

        raise CodegenError(
            "Type has not been assigned to a module yet!", type=self.qname
        )

    def dependencies(self, allow_circular: bool = False) -> Iterator[str]:
        """Yields all class dependencies.

        Omit circular and forward references by default.

        Collect:
            * base classes
            * attribute types
            * attribute choice types
            * recursively go through the inner classes
            * Ignore inner class references
            * Ignore native types.

        Args:
            allow_circular: Allow circular references
        """
        for tp in set(self.types()):
            if tp.is_dependency(allow_circular=allow_circular):
                yield tp.qname

    def types(self) -> Iterator[AttrType]:
        """Yields all class types."""
        for _, tp in self.types_with_parents():
            yield tp

    def types_with_parents(self) -> Iterator[Tuple[CodegenModel, AttrType]]:
        """Yields all class types with their parent codegen instance."""
        for ext in self.extensions:
            yield ext, ext.type

        for attr in self.attrs:
            for tp in attr.types:
                yield attr, tp

            for choice in attr.choices:
                for tp in choice.types:
                    yield choice, tp

        for inner in self.inner:
            yield from inner.types_with_parents()

    def children(self) -> Iterator[CodegenModel]:
        """Yield all codegen children."""
        for attr in self.attrs:
            yield attr
            yield attr.restrictions

            for tp in attr.types:
                yield tp

            for choice in attr.choices:
                yield choice
                yield choice.restrictions

                for tp in choice.types:
                    yield tp

        for ext in self.extensions:
            yield ext
            yield ext.type
            yield ext.restrictions

        for inner in self.inner:
            yield from inner.children()

    def has_forward_ref(self) -> bool:
        """Return whether this class has any forward references."""
        for attr in self.attrs:
            if attr.is_forward_ref:
                return True

            if any(choice for choice in attr.choices if choice.is_forward_ref):
                return True

        return any(inner.has_forward_ref() for inner in self.inner)

    def parent_names(self) -> List[str]:
        """Return the outer class names."""
        result = []
        target = self.parent
        while target is not None:
            result.append(target.name)
            target = target.parent

        return list(reversed(result))

name: str property

Shortcut for the class local name.

slug: str property

Return a slugified version of the class name.

ref: int property

Return this id reference of this instance.

target_namespace: Optional[str] property

Return the class target namespace.

has_suffix_attr: bool property

Return whether it includes a suffix attr.

has_help_attr: bool property

Return whether at least one of attrs has help content.

is_element: bool property

Return whether this class represents a xml element.

is_enumeration: bool property

Return whether all attrs are enumeration members.

is_complex_type: bool property

Return whether this class represents a root/global class.

Global classes are the only classes that get generated by default.

is_group: bool property

Return whether this class is derived from a xs:group/attributeGroup.

is_nillable: bool property

Return whether this class represents a nillable xml element.

is_mixed: bool property

Return whether this class supports mixed content.

is_restricted: bool property

Return whether this class includes any restriction extensions.

is_service: bool property

Return whether this instance is derived from a wsdl:operation.

references: Iterator[int] property

Yield all class object reference numbers.

target_module: str property

Return the designated full module path.

Raises:

Type Description
CodeGenerationError

if the target was not designated a package and module.

dependencies(allow_circular=False)

Yields all class dependencies.

Omit circular and forward references by default.

Collect
  • base classes
  • attribute types
  • attribute choice types
  • recursively go through the inner classes
  • Ignore inner class references
  • Ignore native types.

Parameters:

Name Type Description Default
allow_circular bool

Allow circular references

False
Source code in xsdata/codegen/models.py
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
def dependencies(self, allow_circular: bool = False) -> Iterator[str]:
    """Yields all class dependencies.

    Omit circular and forward references by default.

    Collect:
        * base classes
        * attribute types
        * attribute choice types
        * recursively go through the inner classes
        * Ignore inner class references
        * Ignore native types.

    Args:
        allow_circular: Allow circular references
    """
    for tp in set(self.types()):
        if tp.is_dependency(allow_circular=allow_circular):
            yield tp.qname

types()

Yields all class types.

Source code in xsdata/codegen/models.py
661
662
663
664
def types(self) -> Iterator[AttrType]:
    """Yields all class types."""
    for _, tp in self.types_with_parents():
        yield tp

types_with_parents()

Yields all class types with their parent codegen instance.

Source code in xsdata/codegen/models.py
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
def types_with_parents(self) -> Iterator[Tuple[CodegenModel, AttrType]]:
    """Yields all class types with their parent codegen instance."""
    for ext in self.extensions:
        yield ext, ext.type

    for attr in self.attrs:
        for tp in attr.types:
            yield attr, tp

        for choice in attr.choices:
            for tp in choice.types:
                yield choice, tp

    for inner in self.inner:
        yield from inner.types_with_parents()

children()

Yield all codegen children.

Source code in xsdata/codegen/models.py
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
def children(self) -> Iterator[CodegenModel]:
    """Yield all codegen children."""
    for attr in self.attrs:
        yield attr
        yield attr.restrictions

        for tp in attr.types:
            yield tp

        for choice in attr.choices:
            yield choice
            yield choice.restrictions

            for tp in choice.types:
                yield tp

    for ext in self.extensions:
        yield ext
        yield ext.type
        yield ext.restrictions

    for inner in self.inner:
        yield from inner.children()

has_forward_ref()

Return whether this class has any forward references.

Source code in xsdata/codegen/models.py
706
707
708
709
710
711
712
713
714
715
def has_forward_ref(self) -> bool:
    """Return whether this class has any forward references."""
    for attr in self.attrs:
        if attr.is_forward_ref:
            return True

        if any(choice for choice in attr.choices if choice.is_forward_ref):
            return True

    return any(inner.has_forward_ref() for inner in self.inner)

parent_names()

Return the outer class names.

Source code in xsdata/codegen/models.py
717
718
719
720
721
722
723
724
725
def parent_names(self) -> List[str]:
    """Return the outer class names."""
    result = []
    target = self.parent
    while target is not None:
        result.append(target.name)
        target = target.parent

    return list(reversed(result))

Import dataclass

Python import statement model representation.

Parameters:

Name Type Description Default
qname str

The qualified name of the imported class

required
source str

The absolute module path

required
alias Optional[str]

Specifies an alias to avoid naming conflicts

None
Source code in xsdata/codegen/models.py
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
@dataclass
class Import:
    """Python import statement model representation.

    Args:
        qname: The qualified name of the imported class
        source: The absolute module path
        alias: Specifies an alias to avoid naming conflicts
    """

    qname: str
    source: str
    alias: Optional[str] = field(default=None)

    @property
    def name(self) -> str:
        """Return the name of the imported class."""
        return namespaces.local_name(self.qname)

    @property
    def slug(self) -> str:
        """Return a slugified version of the imported class name."""
        return text.alnum(self.name)

name: str property

Return the name of the imported class.

slug: str property

Return a slugified version of the imported class name.