databind.core
databind.core
Alias
Bases: Setting
The #Alias setting is used to attach one or more alternative names to a dataclass field that should be used instead of the field's name in the code.
Example:
import typing
from dataclasses import dataclass
from databind.core.settings import Alias
@dataclass
class MyClass:
my_field: typing.Annotated[int, Alias('foobar', 'spam')]
When deserializing a payload, converters should now use foobar
if it exists, or fall back to spam
when looking
up the value for the field in the payload as opposed to my_field
. When serializing, converters should use foobar
as the name in the generated payload (always the first alias).
Source code in databind/core/settings.py
BooleanSetting
dataclass
ClassDecoratorSetting
Bases: Setting
Source code in databind/core/settings.py
__call__
Decorate the class type_ with this setting, adding the setting to its __databind_settings__
list
(which is created if it does not exist) and sets #bound_to. The same setting instance cannot decorate multiple
types.
Source code in databind/core/settings.py
Context
dataclass
The context is constructed by the #ObjectMapper and passed to an applicable #Converter to convert #value according to the #datatype.
Source code in databind/core/context.py
convert
get_setting
Retrieve a setting by type that for the current context.
spawn
spawn(value: Any, datatype: Union[TypeHint, Any], key: Union[int, str, None], location: Optional[Location] = None) -> Context
Spawn a sub context with a new value, datatype, key and optionally a new location. If the location is not overwritten, the parent filename is inherited, but not line number and column.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
value |
Any
|
The value to convert. |
required |
datatype |
Union[TypeHint, Any]
|
The datatype of value. If this is not already a #TypeHint, it will be converted to one using #TypeHint(). |
required |
key |
Union[int, str, None]
|
The key or index at which the value can be found relative to the parent. |
required |
location |
Optional[Location]
|
The location of the new value. If not specified, the parent filename is inherited but not the line number and column. |
None
|
Returns: A new #Context object that has self as its #parent.
Source code in databind/core/context.py
ConversionError
Bases: Exception
For any errors that occur during conversion.
Source code in databind/core/converter.py
Converter
Bases: ABC
Interface for converting a value from one representation to another.
Source code in databind/core/converter.py
convert
convert(ctx: Context) -> Any
Convert the value in ctx to another value.
The default implementation will dispatch to #serialize() and #deserialize() depending on the direction given by the context. Because these methods raise #NotImplementedError, an instance of #Converter without custom logic will effectively be a no-op.
Argument
ctx: The conversion context that contains the direction, value, datatype, settings, location and allows you to recursively continue the conversion process for sub values.
Raises:
Type | Description |
---|---|
NotImplementedError
|
If the converter does not support the conversion for the given context. |
NoMatchingConverter
|
If the converter is delegating to other converters, to point out that none of its delegates can convert the value. |
Returns:
Type | Description |
---|---|
Any
|
The new value. |
Source code in databind/core/converter.py
DateFormat
dataclass
Bases: Setting
The #DateFormat setting is used to describe the date format to use for #datetime.datetime, #datetime.date and #datetime.time values when formatting them as a string, i.e. usually when the date/time is serialized, and when parsing them.
The #nr.date module provides types to describe the format of a date, time and datetime (see #date_format,
time_format and #datetime_format), as well as an entire suite of formats for all types of date/time values.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
formats |
T_Input
|
One or more datetime formats to use when parsing. The first of the formats is used for formatting. Each element must be one of the following:
Attempting to use #parse() or #format() for a date/time value type for which the #DateFormat does not provide an applicable format results in a #ValueError. |
()
|
Source code in databind/core/settings.py
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 |
|
format
Format a date/time value to a string.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
dt |
T_Dtype
|
The date/time value to format (i.e. an instance of #datetime.date, #datetime.time or datetime.datetime). |
required |
Raises: ValueError: If no date format to format the type of value is available. Returns: The formatted date/time value.
Source code in databind/core/settings.py
parse
Parse a date/time value from a string.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
type_ |
Type[T_Dtype]
|
The type to parse the value into, i.e. #datetime.date, #datetime.time or #datetime.datetime. |
required |
value |
str
|
The string to parse. |
required |
Raises: ValueError: If no date format is sufficient to parse value into the given type_. Returns: The parsed date/time value.
Source code in databind/core/settings.py
DelegateToClassmethodConverter
Bases: Converter
This converter delegaes to the methods defined by name to perform serialization and deserialization of a type. This converter is usually used in conjunction with settings that override the converteer to be used in a specifc scenario (e.g. such as de/serializing JSON with the #databind.json.settings.JsonConverter setting).
Source code in databind/core/converter.py
DeserializeAs
dataclass
Bases: Setting
Indicates that a field should be deserialized as the given type instead of the type of the field. This is typically used when a field should be typed as an abstract class or interface, but during deserialization of the field, a concrete type should be used instead.
Example:
import typing
from dataclasses import dataclass
from databind.core.settings import DeserializeAs
@dataclass
class A:
pass
@dataclass
class B(A):
pass
@dataclass
class MyClass:
my_field: typing.Annotated[A, DeserializeAs(B)]
Here, although MyClass.my_field
is annotated as A
, when a payload is deserialized into an instance of
MyClass
, the value for my_field
will be deserialized as an instance of B
instead of A
.
Source code in databind/core/settings.py
ExtraKeys
Bases: ClassDecoratorSetting
If discovered while deserializing a #databind.core.schema.Schema, it's callback is used to inform when extras
keys are encountered. If the setting is not available, or if the arg is set to False
(the default), it will
cause an error.
The setting may also be supplied at an individual schema level.
Can be used as a decorator for a class to indicate that extra keys on the schema informed by the class are allowed, as a global setting or as an annotation on a schema field.
Note
Only the first, highest priority annotation is used; thus if you pass a callback for arg it may not be called if the #ExtraKeys setting you pass it to is overruled by another.
Source code in databind/core/settings.py
Field
dataclass
Describes a field in a schema.
Source code in databind/core/schema.py
aliases
property
For convience, the aliases described in the #datatype#'s annotations are listed here. Do note however, that during the conversion process, the #Alias setting should still be looked up through #Context.get_setting() and this field should be ignored. It serves only a introspective purpose. Returns an empty tuple if no alias setting is present in the type hint.
Flattened
dataclass
Bases: BooleanSetting
Indicates whether a field should be "flattened" by virtually expanding it's sub fields into the parent datastructure's serialized form.
Example:
import typing
from dataclasses import dataclass
from databind.core.settings import Flattened
@dataclass
class Inner:
a: int
b: str
@dataclass
class Outter:
inner: typing.Annotated[Inner, Flattened()]
c: str
The Outter
class in the example above may be deserialized, for example, from a JSON payload of the form
{"a": 0, "b": "", "c": ""}
as opposed to {"inner": {"a": 0, "b": ""}, "c": ""}
due to the Outter.inner
field's sub fields being expanded into Outter
.
Source code in databind/core/settings.py
Location
dataclass
Represents a location in a file.
Source code in databind/core/context.py
Module
Bases: Converter
A module is a collection of #Converter#s.
Source code in databind/core/converter.py
NoMatchingConverter
Bases: ConversionError
If no converter matched to convert the value and datatype in the context.
Source code in databind/core/converter.py
ObjectMapper
Bases: Generic[T, U]
The object mapper is responsible for dispatching the conversion process into a #Module.
The type parameter T represents the deserialized type, while U represents the serialized type.
Source code in databind/core/mapper.py
__init__
__init__(settings: Optional[Settings] = None) -> None
Source code in databind/core/mapper.py
convert
convert(direction: Direction, value: Any, datatype: TypeHint | Any, location: Location | None = None, settings: SettingsProvider | List[Setting] | None = None) -> Any
Convert a value according to the given datatype.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
direction |
Direction
|
The direction, i.e. either deserialization or serialization. |
required |
value |
Any
|
The value to convert. |
required |
datatype |
TypeHint | Any
|
The datatype. If not already a #TypeHint instance, it will be converted using #TypeHint(). |
required |
location |
Location | None
|
The location of where value is coming from. Useful to specify to make debugging easier. |
None
|
settings |
SettingsProvider | List[Setting] | None
|
A list of settings, in which case they will be treated as global settings in addition to the mapper's #settings, or an entirely different #SettingsProvider instance (for which it is recommended that it is taking the ObjectMapper's #settings into account, for example by passing them for the Settings.parent). |
None
|
Raises:
Type | Description |
---|---|
ConversionError
|
For more generic errosr during the conversion process. |
NoMatchingConverter
|
If at any point during the conversion a datatype was encountered for which no matching converter was found. |
Source code in databind/core/mapper.py
deserialize
deserialize(value: U, datatype: TypeHint | Any, filename: str | None = None, settings: SettingsProvider | List[Setting] | None = None) -> T
Deserialize value according to the its datatype.
Source code in databind/core/mapper.py
serialize
serialize(value: T, datatype: TypeHint | Any, filename: str | None = None, settings: SettingsProvider | List[Setting] | None = None) -> U
Serialize value according to the its datatype.
Source code in databind/core/mapper.py
Precision
dataclass
Bases: Setting
A setting to describe the precision for #decimal.Decimal fields.
Source code in databind/core/settings.py
Priority
Bases: IntEnum
The priority for settings determines their order in the presence of multiple conflicting settings. Settings should default to using the #NORMAL priority. The other priorities are used to either prevent overriding a field setting globally or to enforce overriding of local field settings globally using #Settings.
Source code in databind/core/settings.py
Remainder
dataclass
Bases: BooleanSetting
This setting can be used to indicate on a field of a schema that is of a mapping type that it consumes any extra keys that are not otherwise understood by the schema. Note that there can only be a maximum of 1 remainder field in the same schema.
Source code in databind/core/settings.py
Required
dataclass
Bases: BooleanSetting
Indicates whether a field is required during deserialization, even if it's type specifies that it is an optional field.
Example:
import typing
from dataclasses import dataclass
from databind.core.settings import Required
@dataclass
class MyClass:
my_field: typing.Annotated[typing.Optional[int], Required()]
Source code in databind/core/settings.py
Schema
dataclass
A #Schema describes a set of fields with a name and datatype.
Source code in databind/core/schema.py
SerializeDefaults
dataclass
Bases: BooleanSetting
Control whether default values are to be encoded in the serialized form of a structure. The default behaviour
is up to the serializer implementation, though we consider it good practices to include values that match the
default value of a field by default. However, using the setting defaults to #enabled having a value of True
due
to how the name of the setting appears assertive of the fact that the instance indicates the setting is enabled.
Source code in databind/core/settings.py
Setting
Base class for types of which instances represent a setting to be taken into account during data conversion. Every setting has a priority that is used to construct and order or to determine the single setting to use in the presence of multiple instances of the same setting type being present.
Settings are usually attached to dataclass fields using #typing.Annotated, or added to a #Settings object for
applying the setting globally, but some subclasses may support being used as decorators to attach the setting
to a type object. Such settings would registers themselves under the __databind_settings__
attribute (created
if it does not exist) such that it can be picked up when introspected by a converter. Such #Setting subclasses
should inherit from #DecoratorSetting instead.
Source code in databind/core/settings.py
Settings
Bases: SettingsProvider
This class is used as a container for other objects that serve as a provider of settings that may taken into account during data conversion. Objects that provide settings are instances of #Setting subclasses, such as
FieldAlias or #DateFormat.
Depending on the type of setting, they may be taken into account if present on a field of a dataclass, or globally from an instance of the #Settings class that is passed to the #ObjectMapper, or both. Which settings are recognized and considered depends also on the implementation of the converter(s) being used.
The #Settings class provides capabilities to supply global settings, as well as supplying settings conditionally based on the type that is being looked at by the #ObjectMapper at the given point in time.
Example:
from databind.core.settings import DateFormat, Priority, Settings, Strict
settings = Settings()
settings.add_global(DateFormat('.ISO_8601', priority=Priority.HIGH))
settings.add_local(int, Strict(false))
Source code in databind/core/settings.py
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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
|
add_conditional
Adds a setting conditional on the given predicate.
Source code in databind/core/settings.py
add_global
add_global(setting: Setting) -> None
add_local
add_local(type_: type, setting: Setting) -> None
Add a setting locally for a particular Python type. If that Python type is encountered, the settings are combined with any other settings that are found for the type.
Source code in databind/core/settings.py
add_provider
Add a provider callback that is invoked for every conversion context to provide additional settings that the subsequent converter should have access to.
Source code in databind/core/settings.py
get_setting
get_setting(context: Context, setting_type: Type[T_Setting]) -> T_Setting | None
Resolves the highest priority instance of the given setting type relevant to the current context. The places that the setting is looked for are, in order:
- If the context's datatype is #AnnotatedTypeHint, look for it in the #AnnotatedTypeHint.metadata. Otherwise, use the wrapped type in the following steps.
- If the datatype is a #ClassTypeHint, look for it as a class setting, then subsequently in the settings added with #add_local().
- Check the setting providers added with #add_provider() or #add_conditional().
- Look for it in the global settings.
- Delegate to the #parent settings provider (if any).
If multiple settings are find using any of these steps, the setting with the highest priority among the settings is returned. If multiple settings have the same priority, the setting found first via the above order is returned.
Source code in databind/core/settings.py
SettingsProvider
Strict
dataclass
Bases: BooleanSetting
Enable strict conversion of the field during conversion (this should be the default for converters unless
some maybe available option to affect the strictness in a converter is changed). This setting should particularly
affect only loss-less type conversions (such as int
to string
and the reverse being allowed when strict
handling is disabled).
Source code in databind/core/settings.py
Union
dataclass
Bases: ClassDecoratorSetting
A setting that decorates a class or can be attached to the #typing.Annotated metadata of a #typing.Union type hint to specify that the type should be regarded as a union of more than one types. Which concrete type is to be used at the point of deserialization is usually clarified through a discriminator key. Unions may be of various styles that dictate how the discriminator key and the remaining fields are to be stored or read from.
For serialiazation, the type of the Python value should inform the converter about which member of the union is being used. If the a union definition has multiple type IDs mapping to the same Python type, the behaviour is entirely up to the converter (an adequate resolution may be to pick the first matching type ID and ignore the remaining matches).
Note
The the examples for the different styles below, "type"
is a stand-in for the value of the #discriminator_key
and ...
serves as a stand-in for the remaining fields of the type that is represented by the discriminator.
Source code in databind/core/settings.py
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 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 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 |
|
__init__
__init__(members: Union[UnionMembers, _MembersMappingType, List[UnionMembers | str | _MembersMappingType], str, None] = None, style: str = NESTED, discriminator_key: str = 'type', nesting_key: Optional[str] = None) -> None
Source code in databind/core/settings.py
register
staticmethod
A convenience method to use as a decorator for classes that should be registered as members of a #Union setting that is attached to the type extends. The #Union setting on extends must have a #StaticUnionMembers
members object. The decorated class must also be a subclass of extends.
Example:
import abc
import dataclasses
from databind.core.settings import Union
@Union()
class MyInterface(abc.ABC):
# ...
pass
@dataclasses.dataclass
@Union.register(MyInterface, 'some')
class SomeImplementation(MyInterface):
# ...
pass
Source code in databind/core/settings.py
convert_dataclass_to_schema
convert_dataclass_to_schema(dataclass_type: Union[type, GenericAlias, ClassTypeHint]) -> Schema
Converts a Python class that is decorated with #dataclasses.dataclass() to a Schema.
The function will respect the #Required setting if it is present in a field's datatype if, and only if, the setting occurs in the root type hint, which must be a #typing.Annotated hint.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
dataclass_type |
Union[type, GenericAlias, ClassTypeHint]
|
A Python type that is a dataclass, or a generic alias of a dataclass. |
required |
Returns: A schema that represents the dataclass. If a generic alias was passed, fields of which the type hint contained type parameters will have their type parameters substituted with the respective arguments present in the alias.
Example:
import dataclasses
from typing import Generic, TypeVar
from typeapi import TypeHint
from databind.core.schema import convert_dataclass_to_schema, Field, Schema
T = TypeVar('T')
@dataclasses.dataclass
class A(Generic[T]):
a: T
assert convert_dataclass_to_schema(A[int]) == Schema({'a': Field(TypeHint(int))}, A)
Source code in databind/core/schema.py
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 216 217 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 |
|
convert_to_schema
convert_to_schema(hint: TypeHint) -> Schema
Convert the given type hint to a #Schema.
The function delegates to #convert_dataclass_to_schema() or #convert_typed_dict_to_schema().
Parameters:
Name | Type | Description | Default |
---|---|---|---|
hint |
TypeHint
|
The type hint to convert. If it is a #AnnotatedTypeHint hint, it will be unwrapped. |
required |
Raises: ValueError: If the type hint is not supported.
Source code in databind/core/schema.py
convert_typed_dict_to_schema
convert_typed_dict_to_schema(typed_dict: Union[TypedDictProtocol, Type[Any], TypeHint]) -> Schema
Converts the definition of a #typing.TypedDict to a #Schema.
Note
This function will take into account default values assigned on the class-level of the typed dict (which is usually only relevant if the class-style declaration method was used, but default values can be assigned to the function-style declared type as well). Fields that have default values are considered not-required even if the declaration specifies them as required.
Be aware that right-hand side values on #typing.TypedDict classes are not allowed by Mypy.
Also note that #typing.TypedDict cannot be mixed with #typing.Generic, so keys with a generic type in the typed dict are not possible (state: 2022-03-17, Python 3.10.2).
Todo
Support understanding #typing.Required and #typing.NotRequired.
Example:
from databind.core.schema import convert_typed_dict_to_schema, Schema, Field
from typing import TypedDict
from typeapi import TypeHint
class Movie(typing.TypedDict):
name: str
year: int = 0
assert convert_typed_dict_to_schema(Movie) == Schema({
'name': Field(TypeHint(str)),
'year': Field(TypeHint(int), False, 0),
}, Movie)
Source code in databind/core/schema.py
format_context_trace
format_context_trace(ctx: Context) -> str
Formats a trace for the given context that is convenient to inspect in case of errors to understand where the context is pointing to in the payload that is being converted.
Source code in databind/core/context.py
get_annotation_setting
Returns the first setting of the given setting_type from the given type hint from inspecting the metadata
of the #AnnotatedTypeHint. Returns None
if no such setting exists or if type_ is not an #AnnotatedTypeHint
instance.
Source code in databind/core/settings.py
get_class_setting
get_class_setting(type_: type, setting_type: Type[T_ClassDecoratorSetting]) -> T_ClassDecoratorSetting | None
Returns the first instance of the given setting_type on type_.
Source code in databind/core/settings.py
get_class_settings
get_class_settings(type_: type, setting_type: Type[T_ClassDecoratorSetting]) -> Iterable[T_ClassDecoratorSetting]
Returns all matching settings on type_.
Source code in databind/core/settings.py
get_fields_expanded
get_fields_expanded(schema: Schema, convert_to_schema: Callable[[TypeHint], Schema] = convert_to_schema) -> Dict[str, Dict[str, Field]]
Returns a dictionary that contains an entry for each flattened field in the schema, mapping to another dictionary that contains all fields expanded from the flattened field's sub-schema.
Given a schema like the following example, this function returns something akin to the below.
=== "Schema"
```
Schema1:
a: int
b: Schema2, flattened=True
Schema2:
c: str
d: Schema3, flattened=True
Schema3:
e: int
```
=== "Result"
```py
{
"b": {
"c": Field(str),
"e": Field(int)
}
}
Arguments: schema: The schema to compile the expanded fields for. convert_to_schema: A function that accepts a #TypeHint and converts it to a schema. Defaults to the #convert_to_schema() function.
Note
The top-level dictionary returned by this function contains only those fields that are flattened and should be "composed" of other fields.
```
Source code in databind/core/schema.py
get_highest_setting
Return the first, highest setting of settings.