Data types¶
How TOONS maps Python values to TOON and back.
Mapping summary¶
| Python | TOON | Notes |
|---|---|---|
dict |
object | Keys are strings; order preserved |
list |
array | Inline or multiline |
str |
string | Quoted only when needed |
int |
integer | No scientific notation |
float |
float | Normalized decimal |
bool |
true/false |
Lowercase |
None |
null |
Strings¶
Strings are unquoted when safe, quoted when required.
Quote a string if it is empty, has leading/trailing whitespace, is numeric-like, equals true/false/null, starts with -, or contains reserved characters (:, ", \, [, ], {, }) or the active delimiter.
import toons
print(toons.dumps({"name": "Alice"}))
# name: Alice
print(toons.dumps({"text": "Hello: World"}))
# text: "Hello: World"
print(toons.loads('text: "Line 1\\nLine 2"'))
# {'text': 'Line 1\nLine 2'}
Numbers¶
TOON uses plain decimal notation. Scientific notation input is expanded.
Booleans and null¶
Objects (dict)¶
Unquoted keys must match $^[A-Za-z_][\w.]*$$. Other keys are quoted.
import toons
print(toons.dumps({"user_id": 1, "full name": "Alice"}))
# user_id: 1
# "full name": Alice
Arrays (list)¶
Primitive arrays are inline; mixed or nested arrays are multiline.
import toons
print(toons.dumps({"tags": ["python", "rust", "toon"]}))
# tags[3]: python,rust,toon
print(toons.dumps({"items": [1, {"a": 1}, True]}))
# items[3]:
# - 1
# - a: 1
# - true
Tabular arrays¶
Uniform arrays of objects can serialize in a compact tabular form.
import toons
data = {"users": [{"id": 1, "name": "A"}, {"id": 2, "name": "B"}]}
print(toons.dumps(data))
# users[2]{id,name}:
# 1,A
# 2,B
Uniform Object Arrays (Tabular):
import toons
users = {
"users": [
{"name": "Alice", "age": 30, "role": "admin"},
{"name": "Bob", "age": 25, "role": "user"},
{"name": "Charlie", "age": 35, "role": "moderator"}
]
}
print(toons.dumps(users))
# users[3]{name,age,role}:
# Alice,30,admin
# Bob,25,user
# Charlie,35,moderator
Requirements for Tabular Format:
- All elements must be objects (dicts)
- All objects must have exactly the same keys
- All values must be primitives (no nested objects/arrays)
Non-Uniform Arrays (Expanded):
import toons
# Mixed types
data = {
"items": [
42,
"text",
{"name": "Alice"},
[1, 2, 3],
None
]
}
print(toons.dumps(data))
# items[5]:
# - 42
# - text
# - name: Alice
# - [3]: 1,2,3
# - null
# Non-uniform objects
data = {
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "role": "admin"} # Different keys
]
}
print(toons.dumps(data))
# users[2]:
# - name: Alice
# age: 30
# - name: Bob
# role: admin
Root Arrays:
import toons
# Root primitive array
data = [1, 2, 3, 4, 5]
print(toons.dumps(data))
# [5]: 1,2,3,4,5
# Root object array (tabular)
data = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
print(toons.dumps(data))
# [2]{name,age}:
# Alice,30
# Bob,25
Type Conversion Table¶
Python → TOON¶
| Python Type | TOON Format | Example |
|---|---|---|
str |
Unquoted or quoted | name: Alice or "name": "Alice" |
int |
Number literal | age: 30 |
float |
Decimal literal | price: 19.99 |
bool |
true / false |
active: true |
None |
null |
value: null |
dict |
Indented key-value | user:\n name: Alice |
list (primitives) |
Inline array | tags[3]: a,b,c |
list (uniform objects) |
Tabular | users[2]{name,age}:\n Alice,30\n Bob,25 |
list (mixed) |
Expanded | items[2]:\n - 1\n - text |
TOON → Python¶
| TOON Format | Python Type | Example |
|---|---|---|
true / false |
bool |
True / False |
null |
NoneType |
None |
| Numeric token | int or float |
42 or 3.14 |
| Unquoted token | str |
"Alice" |
| Quoted string | str |
"Hello\nWorld" |
key: value |
dict |
{"key": "value"} |
key[N]: v1,v2 |
dict with list |
{"key": ["v1", "v2"]} |
| Tabular format | dict with list[dict] |
{"users": [{"name": "Alice"}]} |
Edge Cases¶
Empty Values¶
import toons
# Empty object
data = {}
print(toons.dumps(data))
# (empty string)
# Empty array
data = {"items": []}
print(toons.dumps(data))
# items[0]:
# Empty string
data = {"text": ""}
print(toons.dumps(data))
# text: ""
# Parsing empty
data = toons.loads("")
print(data) # {}
Special Characters¶
import toons
# Strings with delimiters
data = {"csv": "a,b,c"}
print(toons.dumps(data))
# csv: "a,b,c" # Quoted because contains comma
# Strings with colons
data = {"time": "12:30:45"}
print(toons.dumps(data))
# time: "12:30:45" # Quoted because contains colon
# Strings with quotes
data = {"text": 'He said "hello"'}
print(toons.dumps(data))
# text: "He said \"hello\"" # Escaped quotes
Numeric Strings¶
import toons
# Numeric strings must be quoted
data = {"zip": "12345"}
print(toons.dumps(data))
# zip: "12345" # Quoted to preserve as string
# Parsing
data = toons.loads("zip: 12345") # Without quotes
print(data) # {'zip': 12345} # Parsed as number!
data = toons.loads('zip: "12345"') # With quotes
print(data) # {'zip': '12345'} # Preserved as string
Very Large Numbers¶
import toons
# Safe integer range (JavaScript Number.MAX_SAFE_INTEGER)
safe_max = 9007199254740991
data = {"value": safe_max}
print(toons.dumps(data))
# value: 9007199254740991
# Beyond safe range - may lose precision
big = 9007199254740992
data = {"value": big}
result = toons.dumps(data)
parsed = toons.loads(result)
print(parsed["value"] == big) # May be False due to float precision
# Solution: use string for very large numbers
data = {"value": "9007199254740992"}
print(toons.dumps(data))
# value: "9007199254740992" # Preserved exactly
Unsupported Types¶
These Python types cannot be directly serialized:
- Functions / lambdas
- Classes / instances (unless dict-like)
- Modules
- File objects
- Generators
- Custom objects (without conversion)
Workaround: Convert to supported types before serialization:
import toons
from datetime import datetime
# Date objects
date = datetime.now()
data = {"timestamp": date.isoformat()} # Convert to string
print(toons.dumps(data))
# timestamp: 2025-01-01T00:00:00
# Custom objects
class User:
def __init__(self, name, age):
self.name = name
self.age = age
def to_dict(self):
return {"name": self.name, "age": self.age}
user = User("Alice", 30)
data = {"user": user.to_dict()} # Convert to dict
print(toons.dumps(data))
# user:
# name: Alice
# age: 30
Type Preservation¶
TOONS preserves types through round-trip serialization:
import toons
original = {
"string": "hello",
"int": 42,
"float": 3.14,
"bool_true": True,
"bool_false": False,
"null": None,
"array": [1, 2, 3],
"object": {"nested": "value"}
}
# Round-trip
toon_str = toons.dumps(original)
parsed = toons.loads(toon_str)
# Verify types preserved
assert isinstance(parsed["string"], str)
assert isinstance(parsed["int"], int)
assert isinstance(parsed["float"], float)
assert isinstance(parsed["bool_true"], bool)
assert isinstance(parsed["bool_false"], bool)
assert parsed["null"] is None
assert isinstance(parsed["array"], list)
assert isinstance(parsed["object"], dict)
print("✓ All types preserved!")
See Also¶
- API Reference - Function signatures
- Examples - Practical examples
- Specification - TOON format specification