Skip to main content

A high-performance Python library for serialization and deserialization of Python objects to and from JSON. Supports dataclasses, enums, datetime, collections, and more.

Project description

JsonPort

Python License PyPI

A high-performance Python library for seamless serialization and deserialization of complex Python objects to/from JSON format. JsonPort provides intelligent type handling, caching optimizations, and support for dataclasses, enums, datetime objects, and collections.

Features

  • 🚀 High Performance: Optimized with caching for type hints and optional type resolution
  • 🎯 Type Safety: Full type hints support with automatic type conversion
  • 📦 Dataclass Support: Native serialization/deserialization of dataclasses
  • 🗓️ DateTime Handling: Automatic ISO format conversion for datetime objects
  • 🔄 Collection Support: Lists, tuples, sets, and dictionaries with type preservation
  • 📁 File Operations: Direct file I/O with gzip compression support
  • 🎨 Enum Support: Automatic enum value serialization
  • 🛡️ Error Handling: Comprehensive error messages and validation

Installation

pip install jsonport

Python Version Support

JsonPort supports the following Python versions:

  • Python 3.8 - Full support with all features
  • Python 3.9 - Full support with all features
  • Python 3.10 - Full support with all features
  • Python 3.11 - Full support with all features
  • Python 3.12 - Full support with all features
  • Python 3.13 - Full support with all features

All features including dataclasses, type hints, datetime handling, and file operations work consistently across all supported Python versions.

Quick Start

Basic Usage

from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from jsonport import dump, load, dump_file, load_file

# Define your data structures
class UserRole(Enum):
    ADMIN = "admin"
    USER = "user"

@dataclass
class User:
    name: str
    age: int
    role: UserRole
    created_at: datetime
    tags: list[str]

# Create an instance
user = User(
    name="John Doe",
    age=30,
    role=UserRole.ADMIN,
    created_at=datetime.now(),
    tags=["developer", "python"]
)

# Serialize to dictionary
data = dump(user)
print(data)
# Output:
# {
#   "name": "John Doe",
#   "age": 30,
#   "role": "admin",
#   "created_at": "2025-07-14T10:30:00",
#   "tags": ["developer", "python"]
# }

# Deserialize back to object
restored_user = load(data, User)
print(restored_user.name)  # "John Doe"

File Operations

# Save to JSON file
dump_file(user, "user.json")

# Load from JSON file
loaded_user = load_file("user.json", User)

# Save with compression
dump_file(user, "user.json.gz")

# Load compressed file
compressed_user = load_file("user.json.gz", User)

Advanced Examples

Complex Nested Structures

from dataclasses import dataclass
from typing import List, Dict, Optional, Tuple
from datetime import date

@dataclass
class Address:
    street: str
    city: str
    country: str
    postal_code: str

@dataclass
class Contact:
    email: str
    phone: Optional[str] = None

@dataclass
class Company:
    name: str
    founded: date
    employees: int
    address: Address
    contacts: List[Contact]
    departments: Dict[str, List[str]]

# Create complex object
company = Company(
    name="TechCorp",
    founded=date(2020, 1, 1),
    employees=150,
    address=Address(
        street="123 Tech Street",
        city="San Francisco",
        country="USA",
        postal_code="94105"
    ),
    contacts=[
        Contact("info@techcorp.com"),
        Contact("support@techcorp.com", "+1-555-0123")
    ],
    departments={
        "Engineering": ["Backend", "Frontend", "DevOps"],
        "Sales": ["Enterprise", "SMB"],
        "Marketing": ["Digital", "Content"]
    }
)

# Serialize complex structure
data = dump(company)

# Deserialize with full type preservation
restored_company = load(data, Company)

Collections with Type Information

from dataclasses import dataclass
from typing import Set, Tuple

@dataclass
class Product:
    id: int
    name: str
    price: float
    categories: Set[str]
    dimensions: Tuple[float, float, float]

product = Product(
    id=1,
    name="Laptop",
    price=999.99,
    categories={"electronics", "computers", "portable"},
    dimensions=(35.5, 24.0, 2.1)
)

# Serialize with collection type preservation
data = dump(product)
# Sets are converted to lists, tuples preserved
print(data["categories"])  # ["electronics", "computers", "portable"]
print(data["dimensions"])  # [35.5, 24.0, 2.1]

# Deserialize with proper type restoration
restored_product = load(data, Product)
print(type(restored_product.categories))  # <class 'set'>
print(type(restored_product.dimensions))  # <class 'tuple'>

Custom JSON Encoder

import json
from jsonport import JsonPortEncoder

# Use the custom encoder with standard json module
data = dump(company)
json_string = json.dumps(data, cls=JsonPortEncoder, indent=2)
print(json_string)

Error Handling

from jsonport import JsonPortError

try:
    # Try to serialize non-serializable object
    non_serializable = lambda x: x
    dump(non_serializable)
except JsonPortError as e:
    print(f"Serialization error: {e}")

try:
    # Try to load file that doesn't exist
    load_file("nonexistent.json", User)
except FileNotFoundError:
    print("File not found")
except JsonPortError as e:
    print(f"Deserialization error: {e}")

Performance Features

Caching Optimizations

JsonPort automatically caches:

  • Type hints for dataclasses (max 1024 entries)
  • Optional type resolution (max 512 entries)

This provides significant performance improvements when working with the same dataclass types repeatedly.

Benchmarks

import time
from dataclasses import dataclass
from jsonport import dump, load

@dataclass
class BenchmarkData:
    id: int
    name: str
    values: list[float]
    metadata: dict[str, str]

# Create test data
test_data = BenchmarkData(
    id=1,
    name="test",
    values=[1.1, 2.2, 3.3] * 1000,
    metadata={"key1": "value1", "key2": "value2"}
)

# Benchmark serialization
start_time = time.time()
for _ in range(1000):
    data = dump(test_data)
serialization_time = time.time() - start_time

# Benchmark deserialization
start_time = time.time()
for _ in range(1000):
    restored = load(data, BenchmarkData)
deserialization_time = time.time() - start_time

print(f"Serialization: {serialization_time:.4f}s")
print(f"Deserialization: {deserialization_time:.4f}s")

API Reference

Core Functions

dump(obj: Any) -> Any

Serialize a Python object to JSON-serializable format.

Parameters:

  • obj: Object to serialize (dataclass, list, tuple, set, dict, or primitive)

Returns:

  • JSON-serializable dictionary, list, or primitive value

load(data: Any, target_class: Type[T]) -> T

Deserialize JSON data to Python object.

Parameters:

  • data: Dictionary/list to deserialize
  • target_class: Target class for deserialization

Returns:

  • Instance of the target class

dump_file(obj: Any, path: str, overwrite: bool = True) -> None

Serialize object and save to JSON file.

Parameters:

  • obj: Object to serialize
  • path: Path to the JSON file
  • overwrite: If False, raises error when file exists

load_file(path: str, target_class: Type[T]) -> T

Load JSON file and deserialize to object.

Parameters:

  • path: Path to the JSON file
  • target_class: Target class for deserialization

Returns:

  • Instance of the target class

Supported Types

  • Primitives: str, int, float, bool
  • Datetime: datetime.datetime, datetime.date, datetime.time
  • Collections: list, tuple, set, dict
  • Custom Types: dataclass, Enum
  • Optional Types: Optional[T], Union[T, None]

Best Practices

1. Use Type Hints

Always define proper type hints for optimal performance and type safety:

@dataclass
class User:
    name: str
    age: int
    email: Optional[str] = None
    tags: List[str] = None

2. Handle Optional Fields

Use Optional types for fields that might be None:

@dataclass
class Product:
    id: int
    name: str
    description: Optional[str] = None
    price: Optional[float] = None

3. Use Appropriate Collections

Choose the right collection type for your data:

@dataclass
class Configuration:
    settings: Dict[str, Any]
    allowed_users: Set[str]
    coordinates: Tuple[float, float]
    items: List[str]

4. Error Handling

Always handle potential errors in production code:

try:
    data = load_file("config.json", Config)
except (FileNotFoundError, JsonPortError) as e:
    logger.error(f"Failed to load config: {e}")
    data = Config()  # Use default config

Running the Tests

JsonPort uses pytest for all automated tests. To run the test suite:

  1. Install test dependencies (only once):
pip install -e ".[test]"
  1. Run all tests:
pytest -v
  1. Check code coverage:
pytest --cov
  1. Run only fast unit tests (skip slow/integration):
pytest -m 'not slow and not integration' -v
  1. Run only performance tests:
pytest -m slow -v
  1. Run only integration tests:
pytest -m integration -v

All tests are located in the tests/ directory and cover all library features. If you see any errors, make sure you are using Python 3.7+ and all dependencies are installed.


Benchmarking

JsonPort includes performance tests using pytest-benchmark. To run benchmarks and measure serialization/deserialization speed:

pytest --benchmark-only -v

Example output:

--------------------------------------------------------------------------------------------- benchmark: 2 tests -----------------------------------------------------------------------------
Name (time in us)                       Min                 Max                Mean             StdDev              Median                IQR            Outliers  OPS (Kops/s)            Rounds  Iterations
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_deserialization_benchmark     110.3460 (1.0)      263.2940 (1.0)      120.8443 (1.0)      12.3452 (1.0)      118.4470 (1.0)       6.0770 (1.0)       386;464        8.2751 (1.0)        6829           1
test_serialization_benchmark       251.4210 (2.28)     522.7470 (1.99)     270.2584 (2.24)     16.9108 (1.37)     266.3670 (2.25)     12.2920 (2.02)      218;161        3.7002 (0.45)       2499           1
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  • OPS (Kops/s): Operations per second (higher is better)
  • Mean: Average time per operation
  • Rounds/Iterations: Number of repetitions for statistical accuracy

You can compare results between runs or different machines. For more options, see:

pytest --help | grep benchmark

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

Version 1.0.0

  • Initial release
  • High-performance serialization/deserialization
  • Dataclass support with type hints
  • File I/O with gzip compression
  • Comprehensive error handling
  • Caching optimizations for type hints

Support

If you encounter any issues or have questions, please:

  1. Check the documentation
  2. Search existing issues
  3. Create a new issue

JsonPort - Making JSON serialization simple, fast, and type-safe! 🚀

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jsonport-1.0.1.tar.gz (18.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jsonport-1.0.1-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

File details

Details for the file jsonport-1.0.1.tar.gz.

File metadata

  • Download URL: jsonport-1.0.1.tar.gz
  • Upload date:
  • Size: 18.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.10

File hashes

Hashes for jsonport-1.0.1.tar.gz
Algorithm Hash digest
SHA256 6261653265c094142c929bbcfc5f59dcebbf1df4e44645aa377a036246ace0ad
MD5 4f4b1cc7a5e480f305e28b4e8c33efd2
BLAKE2b-256 7d1fc57f643289345aa4cb91cbcd15d59def4a1c03369d33633f167cc059087b

See more details on using hashes here.

File details

Details for the file jsonport-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: jsonport-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 13.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.10

File hashes

Hashes for jsonport-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2ff00d3faad3348a9ac42f1eb776a48d8798a1b21856672dea1ff7c3d00198c3
MD5 860ef55d29224f39ee2eb3eea748feef
BLAKE2b-256 ca1cbcd3e19e7e5e5346f9a23d3ebed46217c8d2f923f9d1cd6ec94aa8bfd021

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page