Basic Usage
This guide covers the fundamental features of Kajson and how to use it as a drop-in replacement for Python's standard json module.
Importing Kajson
You can import Kajson in two ways:
Basic Serialization and Deserialization
Simple Data Types
Kajson handles all standard JSON data types just like the standard json module:
import kajson
# Basic types
data = {
"string": "Hello, World!",
"number": 42,
"float": 3.14159,
"boolean": True,
"null": None,
"list": [1, 2, 3],
"dict": {"nested": "value"}
}
# Serialize to JSON string
json_str = kajson.dumps(data)
# Deserialize back to Python object
restored = kajson.loads(json_str)
assert data == restored # Perfect reconstruction
Formatting Options
Kajson supports all the standard formatting options:
import kajson
data = {"name": "Alice", "age": 30, "skills": ["Python", "JavaScript"]}
# Pretty printing with indentation
print(kajson.dumps(data, indent=2))
# Compact output without spaces
print(kajson.dumps(data, separators=(',', ':')))
# Sort keys alphabetically
print(kajson.dumps(data, sort_keys=True))
# Combine options
print(kajson.dumps(data, indent=4, sort_keys=True))
Working with Files
Writing JSON to Files
import kajson
data = {
"users": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
],
"total": 2
}
# Write to file
with open("data.json", "w") as f:
kajson.dump(data, f, indent=2)
# Alternative: dumps then write
json_str = kajson.dumps(data, indent=2)
with open("data2.json", "w") as f:
f.write(json_str)
Reading JSON from Files
import kajson
# Read from file
with open("data.json", "r") as f:
data = kajson.load(f)
# Alternative: read then loads
with open("data.json", "r") as f:
json_str = f.read()
data = kajson.loads(json_str)
Enhanced Type Support
Unlike standard json, Kajson automatically handles many Python types:
DateTime Objects
import kajson
from datetime import datetime, date, time, timedelta
data = {
"created_at": datetime.now(),
"date_only": date.today(),
"time_only": time(14, 30, 45),
"duration": timedelta(days=7, hours=3)
}
# Serialize and deserialize
json_str = kajson.dumps(data)
restored = kajson.loads(json_str)
# Types are preserved!
assert isinstance(restored["created_at"], datetime)
assert isinstance(restored["duration"], timedelta)
Timezone-Aware Datetimes
Aware datetimes round-trip for every tzinfo flavor β IANA zones (ZoneInfo), fixed offsets (datetime.timezone), and plain UTC:
import kajson
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo
data = {
"utc": datetime.now(timezone.utc),
"paris": datetime(2026, 6, 10, 12, 0, tzinfo=ZoneInfo("Europe/Paris")),
"fixed_offset": datetime.fromisoformat("2026-06-10T12:00:00+02:00"),
}
restored = kajson.loads(kajson.dumps(data))
assert restored == data
The wire format stores both the tzinfo name and the UTC offset, so payloads stay decodable across environments. Decoding prefers the named zone (preserving DST semantics) and falls back to a fixed offset when the name cannot be resolved β for instance on a minimal host whose timezone database is missing. UTC never depends on a timezone database at all. kajson also declares the tzdata package as a dependency, so IANA lookups work out of the box on Windows and on bare containers without system tz files.
Lists and Dictionaries with Complex Types
import kajson
from datetime import datetime
# Complex nested structures
data = {
"timestamps": [datetime.now(), datetime(2025, 1, 1)],
"events": {
"start": datetime(2025, 1, 1, 9, 0),
"end": datetime(2025, 1, 1, 17, 0)
}
}
# Works seamlessly
json_str = kajson.dumps(data)
restored = kajson.loads(json_str)
# All nested types preserved
for ts in restored["timestamps"]:
assert isinstance(ts, datetime)
Advanced Options
Custom Separators
import kajson
data = {"a": 1, "b": 2}
# Default separators
default = kajson.dumps(data)
print(default) # {"a": 1, "b": 2}
# Custom separators for compact output
compact = kajson.dumps(data, separators=(',', ':'))
print(compact) # {"a":1,"b":2}
# Custom separators with spaces
spaced = kajson.dumps(data, separators=(', ', ': '))
print(spaced) # {"a": 1, "b": 2}
Ensure ASCII
import kajson
data = {"greeting": "Hello δΈη π"}
# Default: UTF-8 characters preserved
utf8 = kajson.dumps(data)
print(utf8) # {"greeting": "Hello δΈη π"}
# Ensure ASCII: escape non-ASCII characters
ascii_only = kajson.dumps(data, ensure_ascii=True)
print(ascii_only) # {"greeting": "Hello \\u4e16\\u754c \\ud83c\\udf0d"}
Streaming Large Data
For large datasets, you can use generators and iterative parsing:
import kajson
# Serialize large data in chunks
def generate_large_data():
for i in range(1000000):
yield {"id": i, "value": i * 2}
# Write to file efficiently
with open("large_data.json", "w") as f:
f.write("[")
for i, item in enumerate(generate_large_data()):
if i > 0:
f.write(",")
f.write(kajson.dumps(item))
f.write("]")
Common Patterns
Configuration Files
import kajson
from pathlib import Path
class Config:
def __init__(self, config_path="config.json"):
self.path = Path(config_path)
self.data = self.load()
def load(self):
if self.path.exists():
with open(self.path, "r") as f:
return kajson.load(f)
return {}
def save(self):
with open(self.path, "w") as f:
kajson.dump(self.data, f, indent=2)
def get(self, key, default=None):
return self.data.get(key, default)
def set(self, key, value):
self.data[key] = value
self.save()
# Usage
config = Config()
config.set("api_key", "secret123")
config.set("timeout", 30)
API Responses
import kajson
def create_api_response(data, status="success", message=None):
response = {
"status": status,
"timestamp": kajson.dumps(datetime.now()), # Will be properly serialized
"data": data
}
if message:
response["message"] = message
return kajson.dumps(response, indent=2)
# Usage
user_data = {"id": 123, "name": "Alice"}
response = create_api_response(user_data)
print(response)
Best Practices
-
Always use context managers when working with files:
-
Handle exceptions when loading untrusted data:
-
Use appropriate formatting for your use case:
- Human-readable:
indent=2orindent=4 - Network transmission:
separators=(',', ':')for compact output - Configuration files:
indent=2, sort_keys=Truefor consistency
Next Steps
- Learn about Pydantic Integration for working with data models
- Explore Custom Types to extend Kajson's capabilities
- See Error Handling for robust error management