Simple creation of data classes from dictionaries with advanced type support and validation
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Dacite simplifies the creation of Python data classes from dictionaries. It bridges the gap between raw dictionary data (from HTTP requests, databases, etc.) and strongly-typed data structures, enabling developers to create robust data transfer objects (DTOs) with minimal boilerplate code while maintaining type safety.
pip install dacitefrom dacite import from_dict, ConfigFor exceptions:
from dacite import (
DaciteError,
DaciteFieldError,
WrongTypeError,
MissingValueError,
UnionMatchError,
StrictUnionMatchError,
ForwardReferenceError,
UnexpectedDataError,
)For cache management:
from dacite import set_cache_size, get_cache_size, clear_cachefrom dataclasses import dataclass
from dacite import from_dict
@dataclass
class User:
name: str
age: int
is_active: bool
data = {
'name': 'John',
'age': 30,
'is_active': True,
}
user = from_dict(data_class=User, data=data)
assert user == User(name='John', age=30, is_active=True)The core functionality that converts dictionaries to dataclass instances with full type support and validation.
def from_dict(data_class: Type[T], data: Data, config: Optional[Config] = None) -> T:
"""
Create a data class instance from a dictionary.
Args:
data_class: A data class type to create an instance of
data: Dictionary-like data to convert (must support keys(), __getitem__, __contains__)
config: Optional configuration for controlling the conversion process
Returns:
An instance of the specified data class
Raises:
DaciteError: Base exception for all dacite-related errors
WrongTypeError: When a value has the wrong type for a field
MissingValueError: When a required field is missing from the data
UnionMatchError: When a value cannot match any union type
StrictUnionMatchError: When multiple union types match in strict mode
ForwardReferenceError: When forward references cannot be resolved
UnexpectedDataError: When strict mode encounters unexpected fields
"""Control the conversion process with various options for type handling, validation, and data transformation.
@dataclass
class Config:
"""
Configuration object for controlling from_dict behavior.
Attributes:
type_hooks: Dictionary mapping types to transformation functions
cast: List of types to attempt casting values to
forward_references: Dictionary for resolving forward references
check_types: Enable/disable runtime type checking (default: True)
strict: Enable strict mode to reject unexpected fields (default: False)
strict_unions_match: Enable strict matching for union types (default: False)
convert_key: Function to transform dictionary keys (default: identity function)
"""
type_hooks: Dict[Type, Callable[[Any], Any]]
cast: List[Type]
forward_references: Optional[Dict[str, Any]]
check_types: bool
strict: bool
strict_unions_match: bool
convert_key: Callable[[str], str]Usage example with configuration:
from dacite import from_dict, Config
from dataclasses import dataclass
from typing import Optional
@dataclass
class Person:
name: str
age: Optional[int]
email: str
config = Config(
type_hooks={str: str.strip}, # Strip whitespace from strings
check_types=True, # Enable type checking
strict=True, # Reject unexpected fields
convert_key=lambda key: key.lower() # Convert keys to lowercase
)
data = {"NAME": " John Doe ", "AGE": None, "EMAIL": "john@example.com"}
person = from_dict(Person, data, config)Control internal caching for performance optimization, particularly useful for applications with many dataclass conversions.
def set_cache_size(size: Optional[int]) -> None:
"""
Set the maximum cache size for internal caching.
Args:
size: Maximum cache size (None for unlimited, 0 to disable caching)
"""
def get_cache_size() -> Optional[int]:
"""
Get the current cache size setting.
Returns:
Current cache size (None if unlimited)
"""
def clear_cache() -> None:
"""
Clear all internal caches.
This can be useful for memory management or when type definitions change.
"""Comprehensive exception hierarchy for different error conditions during conversion.
class DaciteError(Exception):
"""Base exception class for all dacite-related errors."""
class DaciteFieldError(DaciteError):
"""
Base class for field-specific errors.
Attributes:
field_path: Path to the problematic field (e.g., 'user.address.street')
"""
field_path: Optional[str]
def update_path(self, parent_field_path: str) -> None:
"""Update the field path with parent context."""
class WrongTypeError(DaciteFieldError):
"""
Raised when a value has the wrong type for a field.
Attributes:
field_type: Expected field type
value: Actual value that caused the error
"""
field_type: Type
value: Any
class MissingValueError(DaciteFieldError):
"""Raised when a required field is missing from the input data."""
class UnionMatchError(WrongTypeError):
"""Raised when a value cannot match any type in a union."""
class StrictUnionMatchError(DaciteFieldError):
"""
Raised when multiple union types match in strict mode.
Attributes:
union_matches: Dictionary of matching types and their converted values
"""
union_matches: Dict[Type, Any]
class ForwardReferenceError(DaciteError):
"""
Raised when forward references cannot be resolved.
Attributes:
message: Error message describing the resolution failure
"""
message: str
class UnexpectedDataError(DaciteError):
"""
Raised when strict mode encounters unexpected fields in the input data.
Attributes:
keys: Set of unexpected field names
"""
keys: Set[str]Automatically converts nested dictionaries to nested dataclasses:
@dataclass
class Address:
street: str
city: str
@dataclass
class Person:
name: str
address: Address
data = {
"name": "John",
"address": {
"street": "123 Main St",
"city": "Anytown"
}
}
person = from_dict(Person, data)Supports complex type annotations including unions and optional fields:
from typing import Union, Optional
@dataclass
class FlexibleData:
value: Union[str, int, float]
optional_field: Optional[str] = None
data = {"value": 42} # optional_field will be None
result = from_dict(FlexibleData, data)Handles lists, tuples, sets, dictionaries, and generic types:
from typing import List, Dict
@dataclass
class Container:
items: List[str]
mapping: Dict[str, int]
data = {
"items": ["a", "b", "c"],
"mapping": {"x": 1, "y": 2}
}
container = from_dict(Container, data)Transform values during conversion using type hooks:
from datetime import datetime
def parse_datetime(value):
return datetime.fromisoformat(value)
@dataclass
class Event:
name: str
timestamp: datetime
config = Config(type_hooks={datetime: parse_datetime})
data = {"name": "Meeting", "timestamp": "2023-01-01T10:00:00"}
event = from_dict(Event, data, config)from typing import Protocol, Any, TypeVar, Type, Optional, Dict, Callable, List, Set
T = TypeVar("T")
class Data(Protocol):
"""
Protocol defining the interface for input data objects.
Any dictionary-like object that supports these methods can be used.
"""
def keys(self) -> Any: ...
def __getitem__(self, *args, **kwargs) -> Any: ...
def __contains__(self, *args, **kwargs) -> bool: ...