Skip to main content

Yapyon (やぴょん)

「YAMLちゃうで。やぴょんやぴょん」 ( It ain't YAML. It's Yapyon.🐇)

Yapyon is a Python-style typed literals with YAML-like block structure, including...

# Comments!

features:
  explicit_literal_types: True        # 'no' != False... or Norway
  lexeme_preserving_templates: True   # 3.10 is displayed 3.10, not 3.1!

ambiguous_conversions: None

builtin:
  - 'byte_encodings'           # Standard, base64, crockford32, hex, etc...
  - 'serializers'              # To JSON, YAML, TOML, and of course Yapyon!

types:
  scalar: ['bool', 'int', 'float', 'str (always quoted!)', 'None']
  containers: ['list', 'dict', 'multimap', 'bytes', 'template strings']

encodings:
  + bytes: b'Python-style' # Same as it ever was...
  + bytes: dna'GATTACA'    # Base-4... and more!
  + int: 0z1A              # Crockford base32 (42, naturally)

The pitch: the same bytes with the same inputs yield the same data, to every parser, on every machine, always. There's no implicit typing: no is not False, and strings are always quoted; there are no anchors or tags, one null spelling, and one document per file. A repeated key in a map is an error, never an uncaught typo silently overwriting data.

Quick-Start Guide

Yapyon is just a pip / pipx / uv install away:

$ pip install yapyon

It can be quickly tested, too:

>>> import yapyon
>>> yapyon.loads('name: "gw"\nport: 8080\naddr: y"{name}:{port}"\n')
{'name': 'gw', 'port': 8080, 'addr': 'gw:8080'}

The loads and load functions return plain Python. Types include builtin Python types as well as OrderedMultimap (+-syntax) and Template (yt-string).

Some other quick commands:

$ python -m yapyon record examples/registry.yap  # A Yapyon record
$ python -m yapyon lexer  examples/gateway.yap   # token dump
$ python -m yapyon parser examples/gateway.yap   # AST dump
$ python -m yapyon tier   examples/gateway.yap   # tier 3 — it carries a yt
$ python -m yapyon expand examples/bridge.yap    # a ledger in, a record out

Read More

Diagnostic Terminology

shiran: (warning) → akan: (error) → yakamashiwa: (internal bug). Verbose success prints ええやん.

Document Variants

A document is one of four kinds (discoverable via yapyon.tier_of()):

  • record: literals only (no resolver / resolution process)
  • ledger: splices & calls built-ins; resolves internally
  • template: incorporates external data (e.g., environment variables)
  • assembly: calls functions that a contract declares; can be assembled from multiple files

Yapyon has no ambient scope nor includes and is built to be completely auditable / verifiable.

Element References

A hole names a value. a.b selects a name key; a["b"] can also select a quoted or computed key. Quoted keys never become names, even when their text looks like an identifier.

protocol: "messenger"
mind:
  endpoint: "https://api.server"
  dialects:
    messenger:
      api_uri: y"{endpoint}/v1"  # reaches its 'uncle' (mind.endpoint)
    icq:
      api_uri: y"{endpoint}/chat"
  chosen: y"{dialects[protocol].api_uri}"   # "https://api.server/v1"
Spelling Means
{a.b} the key b — canonical for identifiers
{a["b.c"]} a key a dot cannot reach
{xs[0]} a list position; brackets only, since 0 is no identifier
{d[p]} the key stored in p, resolved in the y-string's own scope
{mm.k} every value filed under k in a multimap, in order, as a list

{a["bar"]} where a dot would do is a shiran — legal, but say {a.bar}. Because the enclosing string's delimiter ends it, quote a key with the other mark: y"{a['b']}".

Relative References

__ROOT__ names an absolute position; __PARENT__ and __KEY__ name relative ones, so a block can refer to where it is:

store: "/cfg"
personas:
  kisama:
    id:     y"{__PARENT__.__KEY__}"              # -> "kisama"
    prompt: y"{__ROOT__.store}/{__PARENT__.__PARENT__.__KEY__}/{__PARENT__.__KEY__}.md"

The same text in every block, each resolving to its own name — without them a block cannot be renamed or moved without editing its contents. __PARENT__ repeats ({__PARENT__.__PARENT__.x}) and leads a reference; __KEY__ ends one. Bare {__KEY__} is the pair's own key, which is rarely what you want.

Serializers

A container cannot be spliced into text — there is no one text form and picking one would be guessing. Naming the encoding is how it crosses:

store:
  model: "m1"
  host: "https://api.example.com/v1"
body: y"{store.__as_toml__()}"
model = "m1"
host = "https://api.example.com/v1"

__as_json__(), __as_toml__(), __as_yaml__(), and __as_yapyon__() are the format's built-in functions, all written without a runtime dependency, and their output is fixed exactly by SPEC §14 — layout included, so every implementation writes the same text. Keys stay in document order and nothing is pruned. Where a format cannot carry a value directly, the serializer approximates it by that format's own means rather than refusing: bytes become base64url text and a 0xff its value, each with its yapyon spelling recorded beside it in an @_lexemes member; a multimap becomes a JSON-LD node, TOML dotted keys, or YAML !!pairs under a %TAG handle; TOML leaves out a None and records it. A reader that knows the conventions gets the yapyon value back; one that does not still gets correct plain data. YAML scalars are quoted unless every reader would read them as strings, so "no" and "3" survive as strings. {cfg.__as_json__(lexemes=False)} writes the plain values alone.

__as_yapyon__() writes the block as a yapyon record, every value as written: 3.10 still spelled 3.10, multimaps and bytes as themselves. The only thing any serializer refuses is a yt, which has no record form, and __as_toml__() refuses what is not a table, since TOML has no top-level form for anything else.

A serializer names the value it encodes, so it cannot name a bare anchor: {__PARENT__.__as_json__()} would have to encode the string it is computing, and is akan. Reach past the anchor — {__ROOT__.blk.__as_json__()} — which is the shape you want anyway.

Functions and contracts

A hole may call a function — {match_first(supported, mind.dialects)}, or the receiver form {supported.match_first(mind.dialects)} — if the loader is given a contract declaring it. A contract is itself a record:

match_first:
  params:
    keys: "list[str]"
    items: "dict[str, dict[str, str]]"
  returns: "str"
  impl:
    python: {from: "persona_grata.dialects", symbol: "match_first"}
import yapyon

with open("functions.yap") as fp:
    contract = yapyon.load_contract(fp)
with open("persona.yap") as fp:
    data = yapyon.load(fp, contract=contract)

Without from, the loader supplies the code: provide={"match_first": fn}. Arguments may be named, as in Python — {match_first(supported, items=mind.dialects)} — by the contract's parameter names. Arguments are checked against the declared types before the call — deep, and reported where the offending value is written — and a container argument arrives as a read-only, ordered borrow of the document's node. The result is checked against returns and becomes fresh data. Calls nest and chain, and wait for their arguments like any hole, so two calls waiting on each other are reported as the cycle they are. A function that raises is akan naming it, never a traceback. The serializers are the format's built-in functions, called the same way and declared by the spec itself.

Resolving a reference from code

A consumer that assembles a tree from several loaded documents can resolve a reference against it by the same rules a hole uses, without writing its own copy of the search:

tree = yapyon.loads(base)
tree["harness"] = harness = yapyon.loads(harness_doc)
yapyon.lookup(tree, harness, "mind.dialects[protocol].api_uri")

current is the node you are holding, and the answer is the one a y"{...}" written inside it would get: its own keys first, then outward, nearest winning — which is why the tree comes too, since a dict does not know its parents. The whole hole grammar works, serializers included, and an indirect key like [protocol] resolves from current. It is the resolver's own search, so the two cannot disagree. A refusal is an AkanError naming where current sits.

Prefixes (Encodings)

Various binary representations are built into Yapyon to simplify data transfer.

bytes (byte strings)

Prefix Meaning Example Notes
b Standard bytes b'Python-style' Same as it ever was...
b64 RFC 4648 base64 b64'base64//RFC4648=' 4-symbol blocks (padded with '=')
c32 Crockford base32 c32'AllYerCrockford-base 0' Read c32'A11YERCR0CKF0RDBASE0'
hex Hexadecimal hex'badbeef' Read hex'badbeef0' (0-padded, right)
oct Octal oct'10111052' Read oct'10111052' (hex: 20 92 2A)
dna DNA Seq. (base4) dna'GATTACA' Read dna'GATTACAT' (hex E0 98) (0-padded, right)
bin Binary bin'100' Read bin'10000000' (hex 80) (0-padded, right)

int (integers)

Prefix Meaning Example Notes
None Base 10 4 Invented for counting on fingers
0b Binary 0b1000 Read 0b00001000 (0-padded, left)
0q Quaternary 0q33 Read 0q0033 (0-padded, left)
0o Octal 0o20 Read 0o020 (0-padded, left)
0x Hexadecimal 0x17 Read 0x17 (0-padded left; not shown)
0z Crockford base32 0z1A Read 0z01A (0-padded, left)

Variants: bytes / str

Prefix Meaning Example Pronunciation Notes
r Raw str r'chubby\bunny🐇' are-string Same as Python raw str
rb Raw bytes rb'Look\ma\no\escapes!' reeb string Same as Python raw bytes
y yapyon str y'Head like a {desc}' why-string str, spliced at parse
yb yapyon bytes yb'Head like a {desc}' yeeb-string bytes, spliced at parse (holes must be bytes or numbers)
yt yapyon template string yt'{part1}, {part2}' yeet-string Template, unjoined
ry raw yapyon string ry'{part1}{part2}' ree-string str, backslash literal

f"...", t"...", u"..." are errors with hints — their meaning depends on an enclosing scope, and a data file has none.

Metadata

Release files for yapyon 0.5.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yapyon 0.5.2
File Size Uploaded Provenance
yapyon-0.5.2.tar.gz 363.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for yapyon 0.5.2
File Interpreter ABI Platform
yapyon-0.5.2-py3-none-any.whl Python 3 none any Details

Total release size: 511.0 kB

Release files / yapyon-0.5.2.tar.gz

Download URL yapyon-0.5.2.tar.gz
Size 363.8 kB
Tags Source
SHA-256 checksum
How to use checksums
0487d151856011aa4f66bccad92df00a0843c0aa963d7306ffc72ff5b2674603
BLAKE2b-256 checksum
How to use checksums
9caf7e2364d7f5822a8c46474abdbfdfb29a19f8d5f78698095e368d14e1f1d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release files / yapyon-0.5.2-py3-none-any.whl

Download URL yapyon-0.5.2-py3-none-any.whl
Size 147.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1061386f3852452a98ccc5cd6fcb2ab94d834e5d60134f5aa095965897034e24
BLAKE2b-256 checksum
How to use checksums
55724eb9e440faeeb27d1e3120c238f4c80062bd76a919f45e6b1fb754284d9c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Security for yapyon 0.5.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page