-
-
Notifications
You must be signed in to change notification settings - Fork 25
V1: Key Case Transformation
This section provides details about key casing and its transformation in the upcoming v1
major release. Additionally, it highlights the v1
opt-in functionality available in v0.33.0
.
When loading JSON, the default behavior is a 1:1 mapping between JSON keys and dataclass fields. For instance:
- A field named
my_str
in a dataclass maps directly to a JSON keymy_str
.
KeyCase
introduces several key casing transformation options. Shorthand notations (single letters) are available for convenience.
-
C
|CAMEL
: Converts strings to camel case.
Example:my_field_name
→myFieldName
-
P
|PASCAL
: Converts strings to Pascal case (upper camel case).
Example:my_field_name
→MyFieldName
-
K
|KEBAB
: Converts strings to kebab/lisp case.
Example:myFieldName
→my-field-name
-
S
|SNAKE
: Converts strings to snake case.
Example:myFieldName
→my_field_name
-
A
|AUTO
: Automatically maps JSON keys to dataclass fields by trying all valid transformations at runtime. Results are cached for subsequent lookups.
Example:My-Field-Name
→my_field_name
You can override the default behavior using one of the following methods:
@dataclass
class Test(JSONWizard, key_case='C'):
my_str: str
my_bool_test: bool
my_float: float = 1.23
d = {'myStr': 'test', 'myBoolTest': True}
print(repr(Test.from_dict(d)))
# Output: Test(my_str='test', my_bool_test=True, my_float=1.23)
@dataclass
class Test(JSONWizard):
class _(JSONWizard.Meta):
v1 = True
v1_key_case = 'CAMEL'
my_str: str
my_bool_test: bool
my_float: float = 1.23
d = {'myStr': 'test', 'myBoolTest': True, 'MyFloat': 42}
print(repr(Test.from_dict(d)))
# Output: Test(my_str='test', my_bool_test=True, my_float=1.23)
The AUTO
key casing mode (A
) enables automatic detection of valid JSON key casing formats. It sequentially tries:
- Exact match with the dataclass field.
-
camelCase
. -
PascalCase
. -
kebab-case
. -
Upper-Kebab
. -
Upper_Snake
. -
snake_case
.
The transformation result is cached for optimized future lookups.
@dataclass
class Test(JSONWizard, key_case='AUTO'):
my_str: str
my_bool_test: bool
my_int: int
my_float: float = 1.23
d = {'My-Str': 'test', 'myBoolTest': True, 'MyInt': 123, 'my_float': 42}
print(repr(Test.from_dict(d)))
# Output: Test(my_str='test', my_bool_test=True, my_int=123, my_float=42.0)
Note
UPDATE: This issue is resolved in #175. This section is outdated and will be updated shortly to reflect that.
There is one known limitation with the AUTO
key casing transform and aliases in general. In v1
, the library iterates over the dataclass fields instead of the input JSON object o
. This design can lead to issues when multiple JSON keys map to a single dataclass field, as illustrated in the following example:
from dataclasses import dataclass
from dataclass_wizard import LoadMeta, JSONWizard, fromdict
@dataclass
class Container:
id: int
my_elements: list['MyElement']
@dataclass
class MyElement:
order_index: int
status_code: 'int | str'
d = {
'id': '123',
'myElements': [
{'orderIndex': 111, 'statusCode': '200'},
{'order_index': '222', 'status_code': 404}
]
}
LoadMeta(v1=True, v1_key_case='AUTO').bind_to(Container)
# Failure!
c = fromdict(Container, d)
Running the above code results in the following error:
dataclass_wizard.errors.MissingFields: `MyElement.__init__()` is missing required fields.
- Provided: []
- Missing: ['order_index', 'status_code']
- Expected Keys: ['orderIndex', 'statusCode']
- Input JSON: {"order_index": "222", "status_code": 404}
- Key Transform: AUTO
Resolution: Ensure that all required fields are provided in the input. For more details, see:
https://github.com/rnag/dataclass-wizard/discussions/167
This behavior is expected because, with the current v1
implementation, there is no mechanism to map multiple JSON keys to a single dataclass field. As a result, the first key encountered becomes the "alias" for that field.
A test case replicating the example above will be created and marked as a TODO
item for future resolution. This serves as a reminder to address the limitation in a future release.