Marshal dataclasses to/from JSON. Use field properties with initial values. Construct a dataclass schema with JSON input.
Project description
This library provides a set of simple, yet elegant wizarding tools for interacting with the Python dataclasses module.
Full documentation is at:
Features
Here are the supported features that dataclass-wizard currently provides:
JSON (de)serialization: marshal dataclasses to/from JSON and Python dict objects.
Field properties: support for using properties with default values in dataclass instances.
JSON to Dataclass generation: construct a dataclass schema with a JSON file or string input.
Usage
Using the built-in JSON marshalling support for dataclasses:
from dataclasses import dataclass, field
from typing import Optional, List, Tuple
from dataclass_wizard import JSONWizard
@dataclass
class MyClass(JSONWizard):
my_str: Optional[str]
is_active_tuple: Tuple[bool, ...]
list_of_int: List[int] = field(default_factory=list)
string = """
{
"my_str": 20,
"ListOfInt": ["1", "2", 3],
"isActiveTuple": ["true", "false", 1, false]
}
"""
# De-serialize the JSON string into a `MyClass` object.
c = MyClass.from_json(string)
print(repr(c))
# prints:
# MyClass(my_str='20', is_active_tuple=(True, False, True, False), list_of_int=[1, 2, 3])
print(c.to_json())
# prints:
# {"myStr": "20", "isActiveTuple": [true, false, true, false], "listOfInt": [1, 2, 3]}
# True
assert c == c.from_dict(c.to_dict())
… and with the property_wizard, which provides support for field properties with default values in dataclasses:
from dataclasses import dataclass, field
from typing import Union
from typing_extensions import Annotated
from dataclass_wizard import property_wizard
@dataclass
class Vehicle(metaclass=property_wizard):
# Note: The example below uses the default value from the `field` extra in
# the `Annotated` definition; if `wheels` were annotated as a `Union` type,
# it would default to 0, because `int` appears as the first type argument.
#
# Any right-hand value assigned to `wheels` is ignored as it is simply
# re-declared by the property; here it is simply omitted for brevity.
wheels: Annotated[Union[int, str], field(default=4)]
# This is a shorthand version of the above; here an IDE suggests
# `_wheels` as a keyword argument to the constructor method, though
# it will actually be named as `wheels`.
# _wheels: Union[int, str] = 4
@property
def wheels(self) -> int:
return self._wheels
@wheels.setter
def wheels(self, wheels: Union[int, str]):
self._wheels = int(wheels)
if __name__ == '__main__':
v = Vehicle()
print(v)
# prints:
# Vehicle(wheels=4)
v = Vehicle(wheels=3)
print(v)
v = Vehicle('6')
print(v)
assert v.wheels == 6, 'The constructor should use our setter method'
# Confirm that we go through our setter method
v.wheels = '123'
assert v.wheels == 123
… or generate a dataclass schema for JSON input, via the wiz-cli tool:
$ echo '{"myFloat": "1.23", "Products": [{"created_at": "2021-11-17"}]}' | wiz gs - my_file
# Contents of my_file.py
from dataclasses import dataclass
from datetime import date
from typing import List, Union
from dataclass_wizard import JSONWizard
@dataclass
class Data(JSONWizard):
"""
Data dataclass
"""
my_float: Union[float, str]
products: List['Product']
@dataclass
class Product:
"""
Product dataclass
"""
created_at: date
Installing Dataclass Wizard and Supported Versions
The Dataclass Wizard library is available on PyPI:
$ python -m pip install dataclass-wizard
The dataclass-wizard library officially supports Python 3.6 or higher.
JSON Marshalling
JSONSerializable (aliased to JSONWizard) is a Mixin class which provides the following helper methods that are useful for serializing (and loading) a dataclass instance to/from JSON, as defined by the AbstractJSONWizard interface.
Method |
Example |
Description |
---|---|---|
from_json |
item = Product.from_json(string) |
Converts a JSON string to an instance of the dataclass, or a list of the dataclass instances. |
from_list |
list_of_item = Product.from_list(l) |
Converts a Python list object to a list of the dataclass instances. |
from_dict |
item = Product.from_dict(d) |
Converts a Python dict object to an instance of the dataclass. |
to_dict |
d = item.to_dict() |
Converts the dataclass instance to a Python dict object that is JSON serializable. |
to_json |
string = item.to_json() |
Converts the dataclass instance to a JSON string representation. |
Additionally, it adds a default __str__ method to subclasses, which will pretty print the JSON representation of an object; this is quite useful for debugging purposes. Whenever you invoke print(obj) or str(obj), for example, it’ll call this method which will format the dataclass object as a prettified JSON string. If you prefer a __str__ method to not be added, you can pass in str=False when extending from the Mixin class as mentioned here.
Note that the __repr__ method, which is implemented by the dataclass decorator, is also available. To invoke the Python object representation of the dataclass instance, you can instead use repr(obj) or f'{obj!r}'.
To mark a dataclass as being JSON serializable (and de-serializable), simply sub-class from JSONSerializable as shown below. You can also extend from the aliased name JSONWizard, if you prefer to use that instead.
Check out a more complete example of using the JSONSerializable Mixin class.
Supported Types
The Dataclass Wizard library provides inherent support for standard Python collections such as list, dict and set, as well as most Generics from the typing module, such as Union and Any. Other commonly used types such as Enum, defaultdict, and date and time objects such as datetime are also natively supported.
For a complete list of the supported Python types, including info on the load/dump process for special types, check out the Supported Types section in the docs.
Custom Key Mappings
If you ever find the need to add a custom mapping of a JSON key to a dataclass field (or vice versa), the helper function json_field – which can be considered an alias to dataclasses.field() – is one approach that can resolve this.
Example below:
from dataclasses import dataclass
from dataclass_wizard import JSONSerializable, json_field
@dataclass
class MyClass(JSONSerializable):
my_str: str = json_field('myString1', all=True)
# De-serialize a dictionary object with the newly mapped JSON key.
d = {'myString1': 'Testing'}
c = MyClass.from_dict(d)
print(repr(c))
# prints:
# MyClass(my_str='Testing')
# Assert we get the same dictionary object when serializing the instance.
assert c.to_dict() == d
Extending from Meta
Looking to change how date and datetime objects are serialized to JSON? Or prefer that field names appear in snake case when a dataclass instance is serialized?
The inner Meta class allows easy configuration of such settings, as shown below; and as a nice bonus, IDEs should be able to assist with code completion along the way.
from dataclasses import dataclass
from datetime import date
from dataclass_wizard import JSONWizard
from dataclass_wizard.enums import DateTimeTo
@dataclass
class MyClass(JSONWizard):
class _(JSONWizard.Meta):
marshal_date_time_as = DateTimeTo.TIMESTAMP
key_transform_with_dump = 'SNAKE'
my_str: str
my_date: date
data = {'my_str': 'test', 'myDATE': '2010-12-30'}
c = MyClass.from_dict(data)
print(repr(c))
# prints:
# MyClass(my_str='test', my_date=datetime.date(2010, 12, 30))
string = c.to_json()
print(string)
# prints:
# {"my_str": "test", "my_date": 1293685200}
Other Uses for Meta
Here are a few additional use cases for the inner Meta class. Note that a full list of available settings can be found in the Meta section in the docs.
Debug Mode
Enables additional (more verbose) log output. For example, a message can be logged whenever an unknown JSON key is encountered when from_dict or from_json is called.
This also results in more helpful error messages during the JSON load (de-serialization) process, such as when values are an invalid type – i.e. they don’t match the annotation for the field. This can be particularly useful for debugging purposes.
Handle Unknown JSON Keys
The default behavior is to ignore any unknown or extraneous JSON keys that are encountered when when from_dict or from_json is called, and emit a “warning” which is visible when debug mode is enabled (and logging is properly configured). An unknown key is one that does not have a known mapping to a dataclass field.
However, we can also raise an error in such cases if desired. The below example demonstrates a use case where we want to raise an error when an unknown JSON key is encountered in the load (de-serialization) process.
import logging
from dataclasses import dataclass
from dataclass_wizard import JSONWizard
from dataclass_wizard.errors import UnknownJSONKey
# Sets up application logging if we haven't already done so
logging.basicConfig(level='INFO')
@dataclass
class MyClass(JSONWizard):
class _(JSONWizard.Meta):
# True to enable Debug mode for additional (more verbose) log output.
debug_enabled = True
# True to raise an class:`UnknownJSONKey` when an unmapped JSON key is
# encountered when `from_dict` or `from_json` is called.
raise_on_unknown_json_key = True
my_str: str
my_float: float
d = {
'myStr': 'string',
'my_float': '1.23',
# Notice how this key is not mapped to a known dataclass field!
'my_bool': 'Testing'
}
# Try to de-serialize the dictionary object into a `MyClass` object.
try:
c = MyClass.from_dict(d)
except UnknownJSONKey as e:
print('Received error:', type(e).__name__)
print('Unknown JSON key:', e.json_key)
print('JSON object:', e.obj)
print('Known Fields:', e.fields)
else:
print('Successfully de-serialized the JSON object.')
print(repr(c))
Field Properties
The Python dataclasses library has some key limitations with how it currently handles properties and default values.
The dataclass-wizard package natively provides support for using field properties with default values in dataclasses. The main use case here is to assign an initial value to the field property, if one is not explicitly passed in via the constructor method.
To use it, simply import the property_wizard helper function, and add it as a metaclass on any dataclass where you would benefit from using field properties with default values. The metaclass also pairs well with the JSONSerializable mixin class.
For more examples and important how-to’s on properties with default values, refer to the Using Field Properties section in the documentation.
Contributing
Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change.
Check out the Contributing section in the docs for more info.
Credits
This package was created with Cookiecutter and the rnag/cookiecutter-pypackage project template.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file dataclass-wizard-0.11.0.tar.gz
.
File metadata
- Download URL: dataclass-wizard-0.11.0.tar.gz
- Upload date:
- Size: 102.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.9.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2c60e50288207beb87f243b8bdb2de1c54dad012d5140e50baa10bdcd3328f16 |
|
MD5 | 69ac927a68d5fd4bc75b2400e8904df1 |
|
BLAKE2b-256 | 9d9cebf30ad468f85d5a995d3d883ab45a22d523f39d69bdb781b7145b05d787 |
File details
Details for the file dataclass_wizard-0.11.0-py2.py3-none-any.whl
.
File metadata
- Download URL: dataclass_wizard-0.11.0-py2.py3-none-any.whl
- Upload date:
- Size: 65.6 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.9.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 455df4f65dacd34361083539ed8651c576ddb71ad1c1dcf1e7488b66127cefad |
|
MD5 | 9b778c747762d7a55c181021df98e537 |
|
BLAKE2b-256 | a2da26e7a68ee5bbb0cfe332b674faa10c228dd4c07dbfc56c1cb23ee972c2e0 |