A comprehensive dataclass instance creation library that enables bidirectional conversion between dictionaries and dataclass instances.
—
Comprehensive functionality for converting dictionaries and other data structures into dataclass instances. The parsing system handles complex nested types, custom type factories, naming policies, and provides detailed error tracking for debugging.
Main factory class for creating and caching parsers that convert data to dataclass instances. The factory automatically detects types and creates appropriate parsers with caching for performance optimization.
class ParserFactory:
def __init__(
self,
trim_trailing_underscore: bool = True,
debug_path: bool = False,
type_factories: Dict[Type, Parser] = None,
name_styles: Dict[Type, NameStyle] = None,
):
"""
Create a parser factory with configuration options.
Args:
trim_trailing_underscore: Remove trailing underscores from field names
when looking up values in dictionaries (e.g., 'id_' becomes 'id')
debug_path: Enable debug path tracking in exceptions for easier debugging.
Causes some performance decrease but provides detailed error locations
type_factories: Custom parser functions for specific types
name_styles: Naming style mappings per dataclass type
"""
def get_parser(self, cls: ClassVar) -> Parser:
"""
Get or create a parser for the specified class.
Args:
cls: The target class to create parser for (typically a dataclass)
Returns:
Parser function that converts data to instances of cls
"""Simple function for one-off parsing operations without creating a factory instance. Not recommended for repeated use as it recreates the factory each time.
def parse(
data,
cls,
trim_trailing_underscore: bool = True,
type_factories: Dict[Any, Callable] = None,
):
"""
Parse data into an instance of cls using default ParserFactory settings.
Args:
data: The data to parse (typically dict)
cls: Target class to parse into
trim_trailing_underscore: Remove trailing underscores from field names
type_factories: Custom parser functions for specific types
Returns:
Instance of cls created from data
"""from dataclasses import dataclass
from dataclass_factory import ParserFactory
@dataclass
class Product:
name: str
price: float
in_stock: bool = True
parser_factory = ParserFactory()
parser = parser_factory.get_parser(Product)
data = {
"name": "Laptop",
"price": 999.99,
"in_stock": False
}
product = parser(data)
# Result: Product(name="Laptop", price=999.99, in_stock=False)from dataclasses import dataclass
from typing import List, Optional, Union
from dataclass_factory import ParserFactory
@dataclass
class Address:
street: str
city: str
country: str = "USA"
@dataclass
class Person:
name: str
age: int
addresses: List[Address]
phone: Optional[str] = None
id_number: Union[str, int] = None
parser_factory = ParserFactory()
parser = parser_factory.get_parser(Person)
data = {
"name": "John Doe",
"age": 30,
"addresses": [
{"street": "123 Main St", "city": "Anytown"},
{"street": "456 Oak Ave", "city": "Another City", "country": "Canada"}
],
"phone": "+1-555-0123",
"id_number": "ABC123"
}
person = parser(data)from dataclasses import dataclass
from datetime import datetime
from dataclass_factory import ParserFactory
import dateutil.parser
@dataclass
class Event:
name: str
start_time: datetime
duration_minutes: int
# Create parser with custom datetime parsing
parser_factory = ParserFactory(
type_factories={datetime: dateutil.parser.parse}
)
parser = parser_factory.get_parser(Event)
data = {
"name": "Meeting",
"start_time": "2023-12-25T10:00:00",
"duration_minutes": 60
}
event = parser(data)from dataclasses import dataclass
from dataclass_factory import ParserFactory, NameStyle
@dataclass
class ApiResponse:
user_name: str
last_login: str
is_active: bool
# Parse from camelCase JSON
parser_factory = ParserFactory(
name_styles={ApiResponse: NameStyle.camel_lower}
)
parser = parser_factory.get_parser(ApiResponse)
camel_case_data = {
"userName": "johndoe",
"lastLogin": "2023-12-25",
"isActive": True
}
response = parser(camel_case_data)
# Result: ApiResponse(user_name="johndoe", last_login="2023-12-25", is_active=True)from dataclasses import dataclass
from dataclass_factory import ParserFactory
@dataclass
class NestedData:
items: List[Dict[str, int]]
parser_factory = ParserFactory(debug_path=True)
parser = parser_factory.get_parser(NestedData)
try:
# This will fail because "invalid" is not an int
invalid_data = {
"items": [
{"a": 1, "b": 2},
{"c": "invalid", "d": 4} # Error here
]
}
result = parser(invalid_data)
except ValueError as e:
print(f"Error: {e}")
# With debug_path=True, error includes path informationfrom typing import Callable, Any
Parser = Callable[[Any], Any]The parsing system raises ValueError and TypeError exceptions when data cannot be converted to the target type. When debug_path=True is enabled in the ParserFactory, error messages include the full path to the problematic field for easier debugging.
Note: The library internally uses custom exception classes, but these are not part of the public API. Applications should catch standard Python exceptions (ValueError, TypeError) for error handling.
Install with Tessl CLI
npx tessl i tessl/pypi-dataclass-factory