TOML File Handling
The klyn.io.toml package reads and writes TOML 1.1 configuration documents.
It maps tables and arrays to Klyn collections while preserving scalar and temporal types.
import klyn.collections
import klyn.io
import klyn.io.toml
TOML.parse() parses document text. The root value is always a
SortedMap<String, Object>; nested tables are maps and arrays implement
IList<Object>. TOML integers are returned as Long so the full signed
64-bit range remains available.
import klyn.collections
import klyn.io.toml
config = TOML.parse("""title = "Klyn service"
ports = [8080, 8081]
[database]
host = "localhost"
enabled = true
""")
title = config["title"] as String
ports = config["ports"] as IList<Object>
database = config["database"] as SortedMap<String, Object>
assert title == "Klyn service"
assert ports[0] == 8080l
assert database["enabled"] == true
| TOML value | Klyn representation |
|---|---|
| String | String |
| Integer | Long |
Float, inf, nan | Double |
| Boolean | Boolean |
| Offset date-time | DateTime with the parsed fixed offset |
| Local date-time | TOMLLocalDateTime |
| Local date | TOMLLocalDate |
| Local time | TOMLLocalTime |
| Array | ArrayList<Object> |
| Table or inline table | SortedMap<String, Object> |
TOML does not define null. Parsing an unspecified value raises
TOMLParseException, and serializing a Klyn null raises
TOMLWriteException.
Use load() and save() with a filename or a Path. Files are
read and written as UTF-8. Loading validates the byte sequence before parsing and reports malformed
input instead of replacing invalid bytes silently.
import klyn.collections
import klyn.io.toml
config = TOML.load("application.toml")
config["environment"] = "production"
TOML.save("application.toml", config)
The reader and writer overloads integrate with the common klyn.io contracts. Ownership
stays with the caller, so the TOML API never closes a supplied stream.
import klyn.io
import klyn.io.toml
reader = StringReader("port = 8080")
config = TOML.load(reader)
try writer = FileWriter("generated.toml"):
TOML.save(writer, config)
TOML.stringify() produces deterministic text. Nested maps become named tables and a
non-empty list containing only maps becomes an array of tables.
import klyn.collections
import klyn.io.toml
document = {
"title": "Build agents",
"agents": [
{"name": "linux", "enabled": true},
{"name": "windows", "enabled": true}
]
}
print(TOML.stringify(document))
# title = "Build agents"
#
# [[agents]]
# name = "linux"
# enabled = true
#
# [[agents]]
# name = "windows"
# enabled = true
An offset date-time identifies an instant and therefore maps to DateTime. A local date,
local time, or local date-time deliberately has no timezone; dedicated value types preserve that
distinction instead of silently applying the machine's local timezone.
import klyn.io.toml
import klyn.time
values = TOML.parse("""released = 2026-08-10
meeting = 09:30
build = 2026-08-10T09:30
published = 2026-08-10T09:30:00+02:00
""")
assert values["released"] is TOMLLocalDate
assert values["meeting"] is TOMLLocalTime
assert values["build"] is TOMLLocalDateTime
assert values["published"] is DateTime
TOMLParseException exposes one-based line and column properties.
Duplicate keys, conflicting tables, invalid numbers, malformed UTF-8 and invalid escapes are rejected.
TOMLWriteException reports unsupported object types, cycles, excessive nesting and values
outside TOML's data model.
try:
TOML.parse("port = 8080\nport = 9090")
catch error as TOMLParseException:
print(f"{error.line}:{error.column}: {error.message}")
The API exposes a typed data model, not an editable syntax tree. Comments, original whitespace,
numeric bases, quote styles and key order are not promised to survive a parse/stringify round trip.
Also, Klyn strings are zero-terminated and cannot contain U+0000; an escaped TOML NUL is
rejected explicitly rather than truncated.
For the complete format grammar, see the official TOML 1.1 specification.