terset 0.2.1__tar.gz

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.
terset-0.2.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TrueWear, LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
terset-0.2.1/PKG-INFO ADDED
@@ -0,0 +1,132 @@
1
+ Metadata-Version: 2.4
2
+ Name: terset
3
+ Version: 0.2.1
4
+ Summary: Encode JSON records as compact, typed tables.
5
+ Author: TrueWear, LLC
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://terset.dev
8
+ Project-URL: Source, https://github.com/TrueWear/terset
9
+ Keywords: json,llm,prompt,tokens,table,encoding
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Dynamic: license-file
23
+
24
+ # Terset for Python
25
+
26
+ Terset writes JSON records as compact, typed tables using format v2. Python 3.10 or newer.
27
+ Zero runtime dependencies.
28
+
29
+ ## Install
30
+
31
+ Coming soon on PyPI. This package is not published yet.
32
+
33
+ ```sh
34
+ pip install terset
35
+ ```
36
+
37
+ ## Use
38
+
39
+ ```python
40
+ from terset import decode, encode, rules_for
41
+
42
+ data = [{"id": "1", "name": "Ada"}, {"id": "2", "name": "Ben"}]
43
+ text = encode(data)
44
+ print(text)
45
+ print(decode(text) == data)
46
+ ```
47
+
48
+ Output (the gaps are tabs):
49
+
50
+ ```text
51
+ [2]
52
+ id name
53
+ 1 Ada
54
+ 2 Ben
55
+ True
56
+ ```
57
+
58
+ `encode(value)` accepts a dictionary or list at the root. Values can be
59
+ strings, finite numbers, booleans, `None`, dictionaries with string keys,
60
+ and lists. It returns canonical Terset text. Put `rules_for(text)` before the data
61
+ when a reader needs the format explained. It validates canonical text and returns
62
+ the base rules, plus rules for keyed tables and dotted headers when present.
63
+ The exported `RULES` keeps all rules for any text. `decode(text)` returns the same
64
+ JSON value and rejects text the encoder would not produce.
65
+
66
+ Lists of at least two dictionaries become tables when the header and rows
67
+ save UTF-8 bytes. Named tables start with `name[N]:`. Root tables start
68
+ with `[N]` on its own line. Compact JSON lists have no count.
69
+ Missing fields, empty strings and `None` stay distinct.
70
+
71
+ A map in a direct root field can use `name{N}:` when the complete named
72
+ block is strictly shorter than `name: JSON`. Its first column is `@key`,
73
+ which holds each entry's key and is not a field. Root maps stay fields.
74
+ Uniform nested objects with identical ordered simple keys expand into
75
+ dotted headers, recursively. Literal dotted field names are quoted.
76
+ Other nested values stay compact JSON. The decoder rejects count mismatches
77
+ and accepts only the current canonical format.
78
+ See the full [format v2 specification](https://github.com/TrueWear/terset/blob/main/packages/terset/SPEC.md).
79
+
80
+ ## Python details
81
+
82
+ - The format uses JavaScript binary64 numbers. `1.0` writes as `1`.
83
+ Decoded integer literals within `[-2**53, 2**53]` become Python `int`
84
+ values. Tokens with a fraction or exponent, and integers outside this
85
+ range, become `float` values.
86
+ Python integers must be exactly representable as binary64 numbers;
87
+ otherwise encoding raises `TypeError`. This avoids silently rounding
88
+ integers such as `9007199254740993`.
89
+ - Numeric negative zero, infinities, NaN, cycles, non-JSON types and depth
90
+ above 500 raise `TypeError`. Use plain built-in dictionaries and lists.
91
+ - Dictionary order is preserved, with JavaScript's array-index keys first
92
+ in numeric order. For example, `"2"` precedes `"10"`; `"01"` keeps its
93
+ insertion position among other keys.
94
+ - Unicode stays unchanged, including normalization forms and lone
95
+ surrogates. Explicit UTF-16 surrogate pairs become Python astral code
96
+ points. Keys that become identical through this conversion are rejected.
97
+ - Format validation errors raise `ValueError`, including non-finite numbers
98
+ and excessive depth. Passing a non-string to `decode` raises `TypeError`.
99
+
100
+ `encode` uses the covariant `JsonInputRoot` and `JsonInputValue` aliases,
101
+ based on read-only `Mapping` and `Sequence` interfaces. This lets typed
102
+ lists and dictionaries pass without widening their element types. Runtime
103
+ validation still requires plain built-in lists and dictionaries.
104
+ `decode` returns concrete `JsonRoot`, `JsonObject` and `JsonValue` types.
105
+ The package includes `py.typed`.
106
+
107
+ ## Limits
108
+
109
+ The format rejects numeric negative zero and nesting deeper than 500.
110
+ With deep data and an already deep caller stack,
111
+ `encode`, `decode` and `rules_for` can raise `RecursionError`.
112
+ This depends on the available stack depth, not the Python version.
113
+
114
+ ## Local tests
115
+
116
+ From the repository root, without installing the package:
117
+
118
+ ```sh
119
+ python3 -B -m unittest discover -s packages/terset-py/tests -v
120
+ ```
121
+
122
+ Tests read the shared cases generated by the TypeScript encoder and check
123
+ exact output, decoding, the rules string, and invalid inputs. To regenerate
124
+ the cases from the repository root with Node 24:
125
+
126
+ ```sh
127
+ node packages/terset/tests/generate-cases.ts
128
+ ```
129
+
130
+ ## License
131
+
132
+ MIT. Copyright (c) 2026 TrueWear, LLC. The license text is included in `LICENSE`.
terset-0.2.1/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # Terset for Python
2
+
3
+ Terset writes JSON records as compact, typed tables using format v2. Python 3.10 or newer.
4
+ Zero runtime dependencies.
5
+
6
+ ## Install
7
+
8
+ Coming soon on PyPI. This package is not published yet.
9
+
10
+ ```sh
11
+ pip install terset
12
+ ```
13
+
14
+ ## Use
15
+
16
+ ```python
17
+ from terset import decode, encode, rules_for
18
+
19
+ data = [{"id": "1", "name": "Ada"}, {"id": "2", "name": "Ben"}]
20
+ text = encode(data)
21
+ print(text)
22
+ print(decode(text) == data)
23
+ ```
24
+
25
+ Output (the gaps are tabs):
26
+
27
+ ```text
28
+ [2]
29
+ id name
30
+ 1 Ada
31
+ 2 Ben
32
+ True
33
+ ```
34
+
35
+ `encode(value)` accepts a dictionary or list at the root. Values can be
36
+ strings, finite numbers, booleans, `None`, dictionaries with string keys,
37
+ and lists. It returns canonical Terset text. Put `rules_for(text)` before the data
38
+ when a reader needs the format explained. It validates canonical text and returns
39
+ the base rules, plus rules for keyed tables and dotted headers when present.
40
+ The exported `RULES` keeps all rules for any text. `decode(text)` returns the same
41
+ JSON value and rejects text the encoder would not produce.
42
+
43
+ Lists of at least two dictionaries become tables when the header and rows
44
+ save UTF-8 bytes. Named tables start with `name[N]:`. Root tables start
45
+ with `[N]` on its own line. Compact JSON lists have no count.
46
+ Missing fields, empty strings and `None` stay distinct.
47
+
48
+ A map in a direct root field can use `name{N}:` when the complete named
49
+ block is strictly shorter than `name: JSON`. Its first column is `@key`,
50
+ which holds each entry's key and is not a field. Root maps stay fields.
51
+ Uniform nested objects with identical ordered simple keys expand into
52
+ dotted headers, recursively. Literal dotted field names are quoted.
53
+ Other nested values stay compact JSON. The decoder rejects count mismatches
54
+ and accepts only the current canonical format.
55
+ See the full [format v2 specification](https://github.com/TrueWear/terset/blob/main/packages/terset/SPEC.md).
56
+
57
+ ## Python details
58
+
59
+ - The format uses JavaScript binary64 numbers. `1.0` writes as `1`.
60
+ Decoded integer literals within `[-2**53, 2**53]` become Python `int`
61
+ values. Tokens with a fraction or exponent, and integers outside this
62
+ range, become `float` values.
63
+ Python integers must be exactly representable as binary64 numbers;
64
+ otherwise encoding raises `TypeError`. This avoids silently rounding
65
+ integers such as `9007199254740993`.
66
+ - Numeric negative zero, infinities, NaN, cycles, non-JSON types and depth
67
+ above 500 raise `TypeError`. Use plain built-in dictionaries and lists.
68
+ - Dictionary order is preserved, with JavaScript's array-index keys first
69
+ in numeric order. For example, `"2"` precedes `"10"`; `"01"` keeps its
70
+ insertion position among other keys.
71
+ - Unicode stays unchanged, including normalization forms and lone
72
+ surrogates. Explicit UTF-16 surrogate pairs become Python astral code
73
+ points. Keys that become identical through this conversion are rejected.
74
+ - Format validation errors raise `ValueError`, including non-finite numbers
75
+ and excessive depth. Passing a non-string to `decode` raises `TypeError`.
76
+
77
+ `encode` uses the covariant `JsonInputRoot` and `JsonInputValue` aliases,
78
+ based on read-only `Mapping` and `Sequence` interfaces. This lets typed
79
+ lists and dictionaries pass without widening their element types. Runtime
80
+ validation still requires plain built-in lists and dictionaries.
81
+ `decode` returns concrete `JsonRoot`, `JsonObject` and `JsonValue` types.
82
+ The package includes `py.typed`.
83
+
84
+ ## Limits
85
+
86
+ The format rejects numeric negative zero and nesting deeper than 500.
87
+ With deep data and an already deep caller stack,
88
+ `encode`, `decode` and `rules_for` can raise `RecursionError`.
89
+ This depends on the available stack depth, not the Python version.
90
+
91
+ ## Local tests
92
+
93
+ From the repository root, without installing the package:
94
+
95
+ ```sh
96
+ python3 -B -m unittest discover -s packages/terset-py/tests -v
97
+ ```
98
+
99
+ Tests read the shared cases generated by the TypeScript encoder and check
100
+ exact output, decoding, the rules string, and invalid inputs. To regenerate
101
+ the cases from the repository root with Node 24:
102
+
103
+ ```sh
104
+ node packages/terset/tests/generate-cases.ts
105
+ ```
106
+
107
+ ## License
108
+
109
+ MIT. Copyright (c) 2026 TrueWear, LLC. The license text is included in `LICENSE`.
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "terset"
7
+ version = "0.2.1"
8
+ description = "Encode JSON records as compact, typed tables."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "TrueWear, LLC" }]
14
+ dependencies = []
15
+ keywords = ["json", "llm", "prompt", "tokens", "table", "encoding"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Typing :: Typed",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://terset.dev"
30
+ Source = "https://github.com/TrueWear/terset"
31
+
32
+ [tool.setuptools.packages.find]
33
+ where = ["src"]
34
+
35
+ [tool.setuptools.package-data]
36
+ terset = ["py.typed"]
terset-0.2.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ """Encode and decode canonical Terset text without runtime dependencies."""
2
+
3
+ from ._terset import RULES, JsonInputRoot, JsonInputValue, JsonObject, JsonRoot, JsonValue, decode, encode, rules_for
4
+
5
+ __all__ = ["RULES", "JsonInputRoot", "JsonInputValue", "JsonObject", "JsonRoot", "JsonValue", "decode", "encode", "rules_for"]