Skip to content

# Types

## Important

Dataclasses don't validate values when creating a new instances or assigning values to fields. Automatic conversion of values to appropriate python data types occurs only during the parsing process.

The parser handles value/type discrepancies leniently, potentially ignoring the defined field type hint. When such an error arises, the converter issues a `ConverterWarning`.

If you prefer to treat conversion warnings as exceptions you need to activate the ParserConfig.fail_on_converter_warnings option.

## Collections

PEP-585 type hinting generics in standard collections are also supported.

### List

`typing.List`

Case | Example
--- | ---
List | `value: List[str] = field(default_factory=list)`
Optional List | `value: Optional[List[str]] = field(default=None)`
List Union | `value: List[Union[str, int]] = field(default_factory=list)`
Tokens List | `value: List[str] = field(default_factory=list, metadata={"tokens": True})`
List of Tokens | `value: List[List[str]] = field(default_factory=list, metadata={"tokens": True})`

### Tuple

`typing.Tuple` can be use in `frozen` dataclasses, for immutable instances.

Case | Example
--- | ---
Tuple | `value: Tuple[str, ...] = field(default_factory=tuple)`
Optional Tuple | `value: Optional[Tuple[str, ...]] = field(default=None)`
Tuple Union | `value: Tuple[Union[str, int], ...] = field(default_factory=tuple)`
Tokens Tuple | `value: Tuple[str, ...] = field(default_factory=tuple, metadata={"tokens": True})`
Tuple of Tokens | `value: Tuple[Tuple[str, ...], ...] = field(default_factory=tuple, metadata={"tokens": True})`

### Dict

`typing.Dict` is reserved for `Attributes` type fields to capture any undefined attribute.

Case | Example
--- | ---
Attributes | `attrs: Dict[str, str] = field(default_factory=dict, metadata={"type": "Attributes"})`

### Union

`typing.Union`

PEP-604 union types as X | Y are also supported.

Case | Example
--- | ---
Union | `value: Union[str, int, float] = field()`
Optional Union | `value: Optional[Union[str, int, float]] = field(default=None)`

The order of the types doesn't matter, internally the converter sorts the types by priority:

1. `int`
2. `bool`
3. `float`
4. `Decimal`
5. `datetime`
6. `date`
7. `time`
8. `XmlTime`
9. `XmlDate`
10. `XmlDateTime`
11. `XmlDuration`
12. `XmlPeriod`
13. `QName`
14. `str`

## Standard Types

This is the list of all the supported primitive types.

### Boolean

Input | Python | XML | JSON
--- | --- | --- | ---
`"true"` | `True` | `"true"` | `true`
`"1"` | `True` | `"true"` | `true`
`"false"` | `False` | `"false"` | `false`
`"1"` | `False` | `"false"` | `false`

Python Type: [bool][]

XML Type: boolean

### Bytes Array

The fields must provide the `format` metadata property.

- `base16` for hexadecimal string
- `base64` for base64 encoded bytes-like object or ASCII strings

Python Type: [bytes][]

XML Types: hexBinary, base64Binary

### Decimal

Python Type: [decimal.Decimal][]

XML Type: decimal

### Float

Python Type: [float][]

XML Types: double, float

### Integer

Python Type: [int][]

XML Types:

- int
- nonPositiveInteger
- negativeInteger
- long
- integer
- short
- byte
- nonNegativeInteger
- unsignedLong
- unsignedInt
- unsignedShort
- unsignedByte
- positiveInteger

### Object

Python Type: [object][]

XML Type: anySimpleType

### QName

Python Type: [xml.etree.ElementTree.QName][]

XML Types: QName, NOTATION

### String

Python Type: [str][]

XML Types:

- string
- anyURI
- normalizedString
- token
- language
- NMTOKEN
- NMTOKENS
- Name
- NCName
- ID
- IDREF
- IDREFS
- ENTITIES
- ENTITY
- anyAtomicType
- error

### XmlDate

Python Type: xsdata.models.datatype.XmlDate

XML Type: date

### XmlDateTime

Python Type: xsdata.models.datatype.XmlDateTime

XML Types: dateTime, dateTimeStamp

### XmlDuration

Python Type: xsdata.models.datatype.XmlDuration

XML Types:

- duration
- dayTimeDuration
- yearMonthDuration

### XmlPeriod

Python Type: xsdata.models.datatype.XmlPeriod

XML Types:

- gYearMonth
- gYear
- gMonthDay
- gMonth
- gDay

### XmlTime

Python Type: xsdata.models.datatype.XmlTime

XML Type:: time

### Enum

Python Type: [enum.Enum][]

XML Type:: enumeration

## User Types

You can register your own custom types as well as long as they are not dataclasses.

    >>> from dataclasses import dataclass, field
    >>> from xsdata.formats.converter import Converter, converter
    >>> from xsdata.formats.dataclass.parsers import XmlParser
    >>> from xsdata.formats.dataclass.serializers import XmlSerializer
    ...
    >>> serializer = XmlSerializer()
    >>> serializer.config.indent = "  "
    >>> serializer.config.xml_declaration = False
    >>>
    >>> class TheGoodFloat(float):
    ...     pass
    ...
    >>> @dataclass
    ... class Example:
    ...     good: TheGoodFloat = field(metadata=dict(format="{:.2f}"))
    ...     bad: float
    ...
    >>> class TheGoodFloatConverter(Converter):
    ...    def deserialize(self, value: str, **kwargs) -> TheGoodFloat:
    ...        return round(TheGoodFloat(value), 1)  # Even nicer
    ...
    ...    def serialize(self, value: TheGoodFloat, **kwargs) -> str:
    ...        if kwargs["format"]:
    ...            return kwargs["format"].format(value)
    ...        return str(value)
    ...
    >>> converter.register_converter(TheGoodFloat, TheGoodFloatConverter())
    >>> output = serializer.render(Example(TheGoodFloat(10.983263748), -9.9827632))
    >>> print(output)
    <Example>
      <good>10.98</good>
      <bad>-9.9827632</bad>
    </Example>
    >>> XmlParser().from_string(output)
    Example(good=11.0, bad=-9.9827632)

### Overriding standard type converters

It is also possible to override the converter for any of the standard types. For example, we can override the standard serialize function for `XmlDateTime`.

    >>> from dataclasses import dataclass
    >>> from typing import Any, Optional
    >>>
    >>> from xsdata.formats.converter import Converter, converter
    >>> from xsdata.formats.dataclass.parsers import XmlParser
    >>> from xsdata.formats.dataclass.serializers import XmlSerializer
    >>> from xsdata.formats.dataclass.serializers.config import SerializerConfig
    >>> from xsdata.models.datatype import XmlDateTime
    ...
    >>> serializer = XmlSerializer(config=SerializerConfig(xml_declaration=False))
    ...
    ...
    >>> @dataclass
    ... class DateTimeObject:
    ...     datetime: XmlDateTime
    ...
    ...
    >>> datetime_obj = DateTimeObject(
    ...     datetime=XmlDateTime(
    ...         year=2023,
    ...         month=11,
    ...         day=24,
    ...         hour=10,
    ...         minute=38,
    ...         second=56,
    ...         fractional_second=123_000_000,
    ...     )
    ... )
    ...
    >>> print(serializer.render(datetime_obj))
    <DateTimeObject>2023-11-24T10:38:56.123</DateTimeObject>
    >>>
    >>>
    >>> class MyXmlDateTimeConverter(Converter):
    ...     def deserialize(self, value: Any, **kwargs: Any) -> XmlDateTime:
    ...         return XmlDateTime.from_string(value)
    ...
    ...     def serialize(self, value: Any, **kwargs: Any) -> Optional[str]:
    ...         if isinstance(value, XmlDateTime):
    ...             # Can be anything you like
    ...             return (
    ...                 f"{value.day}-{value.month}-{value.year}"
    ...                 f"T{value.hour}:{value.minute}:{value.second}"
    ...             )
    ...
    ...
    >>> converter.register_converter(XmlDateTime, MyXmlDateTimeConverter())
    >>> print(serializer.render(datetime_obj))
    <DateTimeObject>24-11-2023T10:38:56</DateTimeObject>
    >>>
    >>> converter.unregister_converter(XmlDateTime)