A comprehensive Python library for serializing and deserializing Python objects to and from JSON (dictionaries) with minimal code changes required.
81
Advanced configuration options for controlling jsons behavior, including fork management for separate serializer configurations, warning control, verbosity settings, and object transformation utilities.
def fork(fork_inst=StateHolder, name=None):
"""
Create a separate "fork" of serializers and deserializers with independent configuration.
Parameters:
- fork_inst: Base StateHolder class to fork from (defaults to main StateHolder)
- name: Optional name for the new fork (auto-generated if not provided)
Returns:
type: New fork class that can be used as fork_inst parameter in other functions
"""def transform(obj, cls, *, mapper=None, dump_cls=None, dump_args=None, dump_kwargs=None, **kwargs):
"""
Transform an object to a different type via JSON serialization/deserialization.
Parameters:
- obj: Object to be transformed
- cls: Target type to transform into
- mapper: Optional callable to modify the intermediate JSON dict
- dump_cls: Optional type to use when dumping obj (instead of obj's actual type)
- dump_args: Optional list of positional args for dump operation
- dump_kwargs: Optional dict of keyword args for dump operation
- **kwargs: Additional arguments passed to load operation
Returns:
Instance of cls created by transforming obj through JSON
"""def suppress_warnings(do_suppress=True, fork_inst=None):
"""
Suppress or enable jsons warnings globally.
Parameters:
- do_suppress: Bool to control warning suppression (True = suppress, False = enable)
- fork_inst: Optional fork instance to configure (defaults to main StateHolder)
Returns:
None
"""
def suppress_warning(code, fork_inst=None):
"""
Suppress a specific warning by its warning code.
Parameters:
- code: String code of the specific warning to suppress
- fork_inst: Optional fork instance to configure
Returns:
None
"""class Verbosity:
"""
Enum-like class defining levels of verbosity for serialization output.
"""
WITH_NOTHING = 0
WITH_CLASS_INFO = 10
WITH_DUMP_TIME = 20
WITH_EVERYTHING = WITH_CLASS_INFO | WITH_DUMP_TIME
@staticmethod
def from_value(value):
"""
Convert various value types to Verbosity instance.
Parameters:
- value: Value to convert (bool, int, Verbosity, or other)
Returns:
Verbosity: Corresponding Verbosity level
"""import jsons
from jsons import JsonSerializable
from datetime import datetime
from dataclasses import dataclass
# Create separate forks for different use cases
APIFork = jsons.fork(name="APIConfig")
DebugFork = jsons.fork(name="DebugConfig")
# Configure API fork with timestamp serialization
def api_datetime_serializer(dt: datetime, **kwargs) -> int:
return int(dt.timestamp())
# Configure debug fork with verbose datetime serialization
def debug_datetime_serializer(dt: datetime, **kwargs) -> str:
return f"DateTime({dt.isoformat()}, weekday={dt.strftime('%A')})"
# Register different serializers for each fork
jsons.set_serializer(api_datetime_serializer, datetime, fork_inst=APIFork)
jsons.set_serializer(debug_datetime_serializer, datetime, fork_inst=DebugFork)
@dataclass
class Event:
name: str
timestamp: datetime
event = Event("Meeting", datetime(2023, 12, 1, 14, 30, 0))
# Use different forks for different serialization styles
api_json = jsons.dump(event, fork_inst=APIFork)
debug_json = jsons.dump(event, fork_inst=DebugFork)
default_json = jsons.dump(event) # Uses default fork
print("API format:", api_json)
# {'name': 'Meeting', 'timestamp': 1701435000}
print("Debug format:", debug_json)
# {'name': 'Meeting', 'timestamp': 'DateTime(2023-12-01T14:30:00, weekday=Friday)'}
print("Default format:", default_json)
# {'name': 'Meeting', 'timestamp': '2023-12-01T14:30:00'}import jsons
from jsons import JsonSerializable
# Create specialized JsonSerializable classes using forks
APISerializable = JsonSerializable.fork("APISerializable")
InternalSerializable = JsonSerializable.fork("InternalSerializable")
# Configure API fork for external communication
def external_id_serializer(obj_id: int, **kwargs) -> str:
return f"EXT_{obj_id:08d}" # External IDs are string-formatted
jsons.set_serializer(external_id_serializer, int, fork_inst=APISerializable)
class APIUser(APISerializable):
def __init__(self, user_id: int, name: str):
self.user_id = user_id
self.name = name
class InternalUser(InternalSerializable):
def __init__(self, user_id: int, name: str):
self.user_id = user_id
self.name = name
# Same data, different serialization based on fork
api_user = APIUser(12345, "Alice")
internal_user = InternalUser(12345, "Alice")
print("API serialization:", api_user.json)
# {'user_id': 'EXT_00012345', 'name': 'Alice'}
print("Internal serialization:", internal_user.json)
# {'user_id': 12345, 'name': 'Alice'}import jsons
from dataclasses import dataclass
from typing import Dict, Any
@dataclass
class Person:
first_name: str
last_name: str
age: int
@dataclass
class Employee:
name: str
employee_age: int
department: str = "Unassigned"
# Transform Person to Employee with field mapping
def person_to_employee_mapper(person_dict: Dict[str, Any]) -> Dict[str, Any]:
return {
'name': f"{person_dict['first_name']} {person_dict['last_name']}",
'employee_age': person_dict['age'],
'department': 'New Hire'
}
person = Person("John", "Doe", 30)
# Transform using mapper function
employee = jsons.transform(person, Employee, mapper=person_to_employee_mapper)
print(employee)
# Employee(name='John Doe', employee_age=30, department='New Hire')
# Transform with different dump class
@dataclass
class PersonSummary:
first_name: str
age: int
# Note: missing last_name field
summary = jsons.transform(person, PersonSummary, dump_cls=PersonSummary)
print(summary)
# PersonSummary(first_name='John', age=30)import jsons
from dataclasses import dataclass
from typing import List
from datetime import datetime
@dataclass
class LogEntry:
timestamp: datetime
level: str
message: str
module: str
@dataclass
class AlertSummary:
alert_time: str
severity: str
description: str
source: str
# Transform log entries to alert summaries
def log_to_alert_mapper(log_dict):
severity_map = {'ERROR': 'HIGH', 'WARNING': 'MEDIUM', 'INFO': 'LOW'}
return {
'alert_time': log_dict['timestamp'],
'severity': severity_map.get(log_dict['level'], 'UNKNOWN'),
'description': f"Alert: {log_dict['message']}",
'source': f"Module: {log_dict['module']}"
}
log_entries = [
LogEntry(datetime.now(), "ERROR", "Database connection failed", "db_manager"),
LogEntry(datetime.now(), "WARNING", "High memory usage detected", "monitor"),
LogEntry(datetime.now(), "INFO", "User login successful", "auth")
]
# Transform list of logs to list of alerts
alerts = [
jsons.transform(log, AlertSummary, mapper=log_to_alert_mapper)
for log in log_entries
]
for alert in alerts:
print(f"{alert.severity}: {alert.description} ({alert.source})")
# HIGH: Alert: Database connection failed (Module: db_manager)
# MEDIUM: Alert: High memory usage detected (Module: monitor)
# LOW: Alert: User login successful (Module: auth)import jsons
from dataclasses import dataclass
@dataclass
class TestClass:
value: str
# Suppress all warnings
jsons.suppress_warnings(True)
# Code that might generate warnings runs silently
test_obj = TestClass("test")
result = jsons.dump(test_obj)
# Re-enable warnings
jsons.suppress_warnings(False)
# Suppress specific warning by code
jsons.suppress_warning("JSONS001") # Example warning code
# Fork-specific warning control
debug_fork = jsons.fork("DebugFork")
jsons.suppress_warnings(False, fork_inst=debug_fork) # Enable warnings for debug fork
jsons.suppress_warnings(True) # But keep main fork warnings suppressedimport jsons
from jsons import Verbosity, JsonSerializable
from dataclasses import dataclass
from datetime import datetime
@dataclass
class DataPoint:
value: float
recorded_at: datetime
# Different verbosity levels
data = DataPoint(42.5, datetime.now())
# Minimal output (default)
minimal = jsons.dump(data, verbosity=Verbosity.WITH_NOTHING)
print("Minimal:", minimal)
# {'value': 42.5, 'recorded_at': '2023-12-01T14:30:00.123456'}
# With class information
with_class = jsons.dump(data, verbosity=Verbosity.WITH_CLASS_INFO)
print("With class info:", with_class)
# {'value': 42.5, 'recorded_at': '2023-12-01T14:30:00.123456', '-jsons-class': 'DataPoint'}
# With timestamp
with_time = jsons.dump(data, verbosity=Verbosity.WITH_DUMP_TIME)
print("With dump time:", with_time)
# {'value': 42.5, 'recorded_at': '2023-12-01T14:30:00.123456', '-jsons-dump-time': '2023-12-01T14:30:01.000000'}
# With everything
with_all = jsons.dump(data, verbosity=Verbosity.WITH_EVERYTHING)
print("With everything:", with_all)
# {
# 'value': 42.5,
# 'recorded_at': '2023-12-01T14:30:00.123456',
# '-jsons-class': 'DataPoint',
# '-jsons-dump-time': '2023-12-01T14:30:01.000000'
# }
# Verbosity from different value types
print(Verbosity.from_value(True)) # Verbosity.WITH_EVERYTHING
print(Verbosity.from_value(False)) # Verbosity.WITH_NOTHING
print(Verbosity.from_value(None)) # Verbosity.WITH_NOTHINGimport jsons
from jsons import JsonSerializable, Verbosity
# Create a specialized debug configuration
DebugSerializable = JsonSerializable.with_dump(
fork=True, # Create new fork
verbosity=Verbosity.WITH_EVERYTHING,
strict=True
).with_load(
strict=True,
fork=False # Use same fork as dump
)
class DebugModel(DebugSerializable):
def __init__(self, data: str, version: int):
self.data = data
self.version = version
debug_obj = DebugModel("test data", 2)
# Automatically includes verbose information due to fork configuration
debug_json = debug_obj.json
print("Debug JSON includes metadata:", '-jsons-class' in debug_json) # True
# Deserialization uses same fork configuration
restored = DebugModel.from_json(debug_json)
print("Restored:", restored.data, restored.version)import jsons
from jsons import JsonSerializable, Verbosity, KEY_TRANSFORMER_CAMELCASE
from datetime import datetime
from dataclasses import dataclass
# Create a fully configured fork for web API integration
WebAPIFork = jsons.fork("WebAPIConfig")
# Configure datetime serialization for web APIs
def web_datetime_serializer(dt: datetime, **kwargs) -> str:
return dt.isoformat() + 'Z' # ISO format with Z suffix
# Configure custom validation for web objects
def web_string_validator(s: str, **kwargs) -> bool:
if len(s.strip()) == 0:
raise jsons.ValidationError("Web API strings cannot be empty or whitespace")
return True
# Register configurations for the web fork
jsons.set_serializer(web_datetime_serializer, datetime, fork_inst=WebAPIFork)
jsons.set_validator(web_string_validator, str, fork_inst=WebAPIFork)
jsons.suppress_warnings(False, fork_inst=WebAPIFork) # Enable warnings for debugging
# Create a specialized base class
WebAPISerializable = JsonSerializable.fork("WebAPISerializable").with_dump(
fork_inst=WebAPIFork,
key_transformer=KEY_TRANSFORMER_CAMELCASE,
verbosity=Verbosity.WITH_CLASS_INFO
).with_load(
fork_inst=WebAPIFork,
key_transformer=jsons.snakecase,
strict=True
)
@dataclass
class WebUser(WebAPISerializable):
user_name: str
email_address: str
last_login: datetime
is_active: bool
user = WebUser(
user_name="alice_smith",
email_address="alice@example.com",
last_login=datetime.now(),
is_active=True
)
# Serialization uses all configured settings
web_json = user.json
print("Web API JSON:")
print(web_json)
# {
# 'userName': 'alice_smith',
# 'emailAddress': 'alice@example.com',
# 'lastLogin': '2023-12-01T14:30:00.123456Z', # Custom format with Z
# 'isActive': True,
# '-jsons-class': 'WebUser' # Class info due to verbosity setting
# }
# Deserialization handles validation and key transformation
camel_input = {
'userName': 'bob_jones',
'emailAddress': 'bob@example.com',
'lastLogin': '2023-12-01T15:30:00.000000Z',
'isActive': False
}
restored_user = WebUser.from_json(camel_input)
print("Restored user:", restored_user.user_name, restored_user.email_address)Install with Tessl CLI
npx tessl i tessl/pypi-jsonsdocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10