CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-jsons

A comprehensive Python library for serializing and deserializing Python objects to and from JSON (dictionaries) with minimal code changes required.

81

1.65x
Overview
Eval results
Files

type-system.mddocs/

Type System

Comprehensive support for Python's type system including built-in types, collections, datetime objects, Enum types, Union types, and custom objects. The jsons library provides default serializers and deserializers for all common Python types with intelligent type inference.

Capabilities

Built-in Type Support

jsons automatically handles serialization and deserialization for these Python types:

Primitive Types

  • str - String values (no conversion needed)
  • int - Integer numbers
  • float - Floating-point numbers
  • bool - Boolean values (True/False)
  • None - Null values

Numeric Types

  • complex - Complex numbers (serialized as dict with 'real' and 'imag' keys)
  • Decimal - High-precision decimal numbers (serialized as string)

Collection Types

  • list - Lists and List[T] type hints
  • tuple - Tuples and Tuple[T, ...] type hints
  • dict - Dictionaries and Dict[K, V] type hints
  • set - Sets (serialized as lists)
  • frozenset - Frozen sets (serialized as lists)
  • DefaultDict - Default dictionaries with default factory preservation

Date and Time Types

  • datetime - Date and time objects (ISO format strings)
  • date - Date objects (ISO date strings)
  • time - Time objects (ISO time strings)
  • timezone - Timezone objects
  • timedelta - Time duration objects
  • ZoneInfo - Timezone info objects (Python 3.9+)

Other Built-in Types

  • UUID - Universally unique identifiers (serialized as strings)
  • Enum - Enumeration values (serialized as enum values)
  • IntEnum - Integer enumeration values
  • pathlib.Path - Path objects (serialized as strings)
  • Mapping - Abstract base class for mappings
  • Iterable - Abstract base class for iterables

Generic Type Support

# Automatic handling of typing module generics:
# List[T], Tuple[T, ...], Dict[K, V], Set[T], FrozenSet[T]
# Union[T1, T2, ...], Optional[T], DefaultDict[K, V]
# Mapping[K, V], Iterable[T]

Usage Examples

Primitive and Numeric Types

import jsons
from decimal import Decimal

# Primitive types work automatically
data = {
    'name': 'John',           # str
    'age': 30,                # int  
    'height': 5.9,            # float
    'is_active': True,        # bool
    'notes': None             # NoneType
}

serialized = jsons.dump(data)
restored = jsons.load(serialized, dict)
print(restored == data)  # True

# Complex numbers  
complex_num = 3 + 4j
serialized = jsons.dump(complex_num)
print(serialized)  # {'real': 3.0, 'imag': 4.0}
restored = jsons.load(serialized, complex)
print(restored)  # (3+4j)

# Decimal precision
price = Decimal('19.99')
serialized = jsons.dump(price)
print(serialized)  # '19.99'
restored = jsons.load(serialized, Decimal)
print(restored == price)  # True

Collection Types

import jsons
from typing import List, Dict, Tuple, Set, Optional
from collections import defaultdict

# Lists with type hints
numbers: List[int] = [1, 2, 3, 4, 5]
serialized = jsons.dump(numbers)
restored = jsons.load(serialized, List[int])
print(restored)  # [1, 2, 3, 4, 5]

# Dictionaries with type hints
scores: Dict[str, int] = {'Alice': 95, 'Bob': 87, 'Charlie': 92}
serialized = jsons.dump(scores) 
restored = jsons.load(serialized, Dict[str, int])
print(restored)  # {'Alice': 95, 'Bob': 87, 'Charlie': 92}

# Tuples with specific types
coordinates: Tuple[float, float, str] = (40.7128, -74.0060, 'NYC')
serialized = jsons.dump(coordinates)
restored = jsons.load(serialized, Tuple[float, float, str])
print(restored)  # (40.7128, -74.006, 'NYC')

# Sets (serialized as lists)
unique_tags: Set[str] = {'python', 'json', 'serialization'}
serialized = jsons.dump(unique_tags)
print(serialized)  # ['python', 'json', 'serialization'] (order may vary)
restored = jsons.load(serialized, Set[str]) 
print(type(restored))  # <class 'set'>

# DefaultDict with factory function preservation
def_dict = defaultdict(list)
def_dict['fruits'].extend(['apple', 'banana'])
def_dict['vegetables'].extend(['carrot', 'broccoli'])

serialized = jsons.dump(def_dict)
restored = jsons.load(serialized, defaultdict)
print(restored['new_key'])  # [] (default factory still works)

Date and Time Types

import jsons
from datetime import datetime, date, time, timezone, timedelta
from zoneinfo import ZoneInfo  # Python 3.9+

# Datetime objects
now = datetime.now()
serialized = jsons.dump(now)
print(serialized)  # '2023-12-01T10:30:00.123456'
restored = jsons.load(serialized, datetime)
print(type(restored))  # <class 'datetime.datetime'>

# Date objects
today = date.today()
serialized = jsons.dump(today)
print(serialized)  # '2023-12-01'
restored = jsons.load(serialized, date)

# Time objects  
current_time = time(14, 30, 45)
serialized = jsons.dump(current_time)
print(serialized)  # '14:30:45'
restored = jsons.load(serialized, time)

# Timezone-aware datetime
utc_time = datetime.now(timezone.utc)
serialized = jsons.dump(utc_time)
restored = jsons.load(serialized, datetime)
print(restored.tzinfo)  # timezone.utc

# Timedelta objects
duration = timedelta(days=7, hours=3, minutes=30)
serialized = jsons.dump(duration)
restored = jsons.load(serialized, timedelta)
print(restored.days)  # 7

# ZoneInfo (Python 3.9+)
ny_tz = ZoneInfo('America/New_York')
ny_time = datetime.now(ny_tz)
serialized = jsons.dump(ny_time)
restored = jsons.load(serialized, datetime)

Enum and Special Types

import jsons
from enum import Enum, IntEnum
from uuid import uuid4, UUID
from pathlib import Path

# Enum types
class Status(Enum):
    PENDING = 'pending'
    APPROVED = 'approved'  
    REJECTED = 'rejected'

class Priority(IntEnum):
    LOW = 1
    MEDIUM = 2
    HIGH = 3

status = Status.APPROVED
priority = Priority.HIGH

status_serialized = jsons.dump(status)
priority_serialized = jsons.dump(priority)

print(status_serialized)   # 'approved'
print(priority_serialized) # 2

status_restored = jsons.load(status_serialized, Status)
priority_restored = jsons.load(priority_serialized, Priority)

print(status_restored == Status.APPROVED)  # True
print(priority_restored == Priority.HIGH)  # True

# UUID objects
unique_id = uuid4()
serialized = jsons.dump(unique_id)
print(serialized)  # '12345678-1234-5678-1234-567812345678'
restored = jsons.load(serialized, UUID)
print(type(restored))  # <class 'uuid.UUID'>

# Path objects
file_path = Path('/home/user/documents/file.txt')
serialized = jsons.dump(file_path)
print(serialized)  # '/home/user/documents/file.txt'
restored = jsons.load(serialized, Path)
print(type(restored))  # <class 'pathlib.PosixPath'>

Union and Optional Types

import jsons
from typing import Union, Optional, List
from dataclasses import dataclass

@dataclass
class NumberContainer:
    value: Union[int, float, str]  # Can be int, float, or str
    optional_notes: Optional[str] = None  # Can be str or None

# Union types - jsons automatically detects the correct type
containers = [
    NumberContainer(42),           # int
    NumberContainer(3.14),         # float  
    NumberContainer("not_a_number"), # str
    NumberContainer(100, "Important note")  # with optional field
]

serialized_list = jsons.dump(containers)
print(serialized_list)
# [
#   {'value': 42, 'optional_notes': None},
#   {'value': 3.14, 'optional_notes': None}, 
#   {'value': 'not_a_number', 'optional_notes': None},
#   {'value': 100, 'optional_notes': 'Important note'}
# ]

restored_list = jsons.load(serialized_list, List[NumberContainer])
print(type(restored_list[0].value))  # <class 'int'>
print(type(restored_list[1].value))  # <class 'float'>  
print(type(restored_list[2].value))  # <class 'str'>

# Optional types work seamlessly
@dataclass  
class User:
    username: str
    email: Optional[str] = None

user1 = User("alice")  # email is None
user2 = User("bob", "bob@example.com")  # email provided

users = [user1, user2]
serialized = jsons.dump(users)
restored = jsons.load(serialized, List[User])

print(restored[0].email)  # None
print(restored[1].email)  # 'bob@example.com'

Custom Object Support

import jsons
from dataclasses import dataclass
from typing import List

@dataclass
class Address:
    street: str
    city: str
    zip_code: str

@dataclass
class Person:
    name: str
    age: int
    address: Address
    phone_numbers: List[str]

# Nested custom objects work automatically with type hints
address = Address("123 Main St", "Anytown", "12345")
person = Person("John Doe", 30, address, ["+1-555-0100", "+1-555-0101"])

# Automatic serialization of nested objects
serialized = jsons.dump(person)
print(serialized)
# {
#   'name': 'John Doe',
#   'age': 30,
#   'address': {'street': '123 Main St', 'city': 'Anytown', 'zip_code': '12345'},
#   'phone_numbers': ['+1-555-0100', '+1-555-0101']
# }

# Automatic deserialization with proper type reconstruction
restored = jsons.load(serialized, Person)
print(type(restored.address))  # <class '__main__.Address'>
print(restored.address.city)   # 'Anytown'
print(len(restored.phone_numbers))  # 2

Generic Collections with Custom Objects

import jsons
from dataclasses import dataclass  
from typing import Dict, List, Optional
from datetime import datetime

@dataclass
class Task:
    id: int
    title: str
    completed: bool
    due_date: Optional[datetime] = None

@dataclass
class Project:
    name: str
    tasks: Dict[str, List[Task]]  # Complex nested generic structure

# Complex nested structures with multiple generics
project = Project(
    name="Website Redesign",
    tasks={
        "frontend": [
            Task(1, "Create mockups", False, datetime(2023, 12, 15)),
            Task(2, "Implement UI", False, datetime(2023, 12, 20))
        ],
        "backend": [
            Task(3, "API design", True),
            Task(4, "Database schema", False, datetime(2023, 12, 10))  
        ]
    }
)

# Serialize complex nested structure
serialized = jsons.dump(project)
print(serialized['tasks']['frontend'][0]['title'])  # 'Create mockups'

# Deserialize with full type reconstruction
restored = jsons.load(serialized, Project)
print(type(restored.tasks))  # <class 'dict'>
print(type(restored.tasks['frontend']))  # <class 'list'>
print(type(restored.tasks['frontend'][0]))  # <class '__main__.Task'>
print(type(restored.tasks['frontend'][0].due_date))  # <class 'datetime.datetime'>

Install with Tessl CLI

npx tessl i tessl/pypi-jsons

docs

class-integration.md

configuration.md

core-serialization.md

customization.md

index.md

key-transformation.md

type-system.md

tile.json