yapyon 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
yapyon/__init__.py ADDED
@@ -0,0 +1,58 @@
1
+ """yapyon — YAMLちゃうで。やぴょんやぴょん。
2
+
3
+ Python-style typed literals with YAML-like block structure.
4
+ Home: https://github.com/doctorjei/yapyon
5
+
6
+ >>> import yapyon
7
+ >>> yapyon.loads('name: "gw"\\nbanner: y"{name} v1"\\n')
8
+ {'name': 'gw', 'banner': 'gw v1'}
9
+
10
+ **Conformance (SPEC §12.5): this implementation provides the full form**,
11
+ and therefore also loads yapyon records — `loads_record`, `load_record` and
12
+ `is_record` are the record surface.
13
+
14
+ **Identifier tables (GRAMMAR §G4.1): pinned to Unicode 14.0.0.** yapyon
15
+ ships its own table rather than asking `str.isidentifier()`, whose answer
16
+ depends on the interpreter, so a key means the same thing on every install.
17
+ `UNICODE_VERSION` is that pinned version.
18
+ """
19
+
20
+ from ._xid import UNICODE_VERSION as _XID_UNICODE_VERSION
21
+ from .lexer import Lexer, Token, tokenize, AkanError, Yakamashiwa
22
+ from .parser import (Mapping, MultiMap, Node, Pair, Parser, Scalar, Sequence,
23
+ ResolvedTemplate, YString, dump, parse,
24
+ parse_tokens)
25
+ from .resolver import Resolver, resolve
26
+ from .multimap import Entry, KeyView, OrderedMultimap
27
+ from .template import Hole, Template
28
+ from .loader import build, is_record, load, load_record, loads, loads_record
29
+ from .emitter import emit
30
+
31
+ __version__ = "0.1.0"
32
+
33
+ #: GRAMMAR §G4.1 asks every implementation to document where its identifier
34
+ #: tables come from. yapyon's are generated from this Unicode version by
35
+ #: tools/gen_xid_table.py, and do not vary with the interpreter.
36
+ UNICODE_VERSION = _XID_UNICODE_VERSION
37
+
38
+ __all__ = [
39
+ # what this install's identifier tables are (GRAMMAR §G4.1)
40
+ "UNICODE_VERSION",
41
+ # the everyday API
42
+ "load", "loads", "build", "Template", "Hole", "OrderedMultimap",
43
+ # records — the fixed, literal-only form
44
+ "load_record", "loads_record", "is_record",
45
+ # a record AST back to canonical yapyon source (python -m yapyon.record)
46
+ "emit",
47
+ # diagnostics
48
+ "AkanError", "Yakamashiwa",
49
+ # the stages, for tools that want them
50
+ "Lexer", "Token", "tokenize",
51
+ "Parser", "parse", "parse_tokens", "dump",
52
+ "Resolver", "resolve",
53
+ # AST
54
+ "Node", "Scalar", "YString", "ResolvedTemplate", "Pair", "Mapping",
55
+ "Sequence", "MultiMap",
56
+ # multimap internals
57
+ "Entry", "KeyView",
58
+ ]
yapyon/__main__.py ADDED
@@ -0,0 +1,39 @@
1
+ """`python -m yapyon <stage> [FILE]` — the stages, from the command line.
2
+
3
+ python -m yapyon lexer FILE # token dump
4
+ python -m yapyon parser FILE # AST dump
5
+ python -m yapyon record FILE # a record, normalized back to yapyon
6
+
7
+ Prefer this spelling over `python -m yapyon.lexer`. Both work, but the
8
+ per-module form re-executes a module the package has already imported, which
9
+ makes CPython print a `RuntimeWarning` onto the very stream the diagnostics
10
+ use — and, before this indirection existed, gave the stage a second copy of
11
+ `AkanError` that `_cli` could not catch.
12
+
13
+ Diagnostics go to stderr, output to stdout, and a shiran does not change the
14
+ exit status; `_cli` holds those rules.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import sys
20
+
21
+ STAGES = ("lexer", "parser", "record")
22
+
23
+
24
+ def main(argv: list[str]) -> int:
25
+ if len(argv) < 2 or argv[1] in ("-h", "--help"):
26
+ print(__doc__.strip(), file=sys.stderr)
27
+ return 0 if len(argv) > 1 else 2
28
+ stage, rest = argv[1], argv[2:]
29
+ if stage not in STAGES:
30
+ print(f"akan: no such stage {stage!r}; try one of "
31
+ f"{', '.join(STAGES)}", file=sys.stderr)
32
+ return 2
33
+ from importlib import import_module
34
+ module = import_module(f".{stage}", __package__)
35
+ return module.main([f"yapyon {stage}", *rest])
36
+
37
+
38
+ if __name__ == "__main__":
39
+ sys.exit(main(sys.argv))
yapyon/_cli.py ADDED
@@ -0,0 +1,46 @@
1
+ """Shared plumbing for the `python -m yapyon.*` entry points.
2
+
3
+ Three rules live here, once, because four copies of them would drift:
4
+
5
+ * **Shirans go to stderr and are shown by default.** The library keeps them
6
+ behind `warn=` — a caller may not want them — but a person at a terminal
7
+ asked to see what the tool thinks, so a CLI that swallowed them would be
8
+ hiding the only warning rung the format has.
9
+ * **A shiran never changes the exit status.** It is legal-but-suspicious, not
10
+ an error; a pipeline consuming stdout must not break because of one.
11
+ * **Diagnostics never go to stdout.** `python -m yapyon.record` writes yapyon
12
+ there and its output is meant to be redirected, so an akan or a shiran on
13
+ stdout would corrupt the file it is being written into.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import sys
19
+
20
+ from .lexer import AkanError
21
+
22
+
23
+ def source_from(argv: list[str]) -> tuple[str, str | None]:
24
+ """The file named on the command line, or stdin. The name is returned so
25
+ diagnostics can carry it — `f.ypy:3:9` rather than `line 3, col 9`."""
26
+ name = argv[1] if len(argv) > 1 else None
27
+ text = open(name, encoding="utf-8").read() if name else sys.stdin.read()
28
+ return text, name
29
+
30
+
31
+ def run(argv: list[str], work) -> int:
32
+ """`work(text, source) -> (stdout_text, warnings)`, wrapped in the rules.
33
+
34
+ Warnings are written before the output: they are diagnostics *about* the
35
+ input, and on a terminal a long dump would otherwise scroll them away.
36
+ """
37
+ text, name = source_from(argv)
38
+ try:
39
+ out, warnings = work(text, name)
40
+ except AkanError as exc:
41
+ print(exc, file=sys.stderr)
42
+ return 1
43
+ for warning in warnings:
44
+ print(warning, file=sys.stderr)
45
+ sys.stdout.write(out)
46
+ return 0