gcf-python 0.5.0__tar.gz → 1.0.0__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.
- gcf_python-1.0.0/.github/FUNDING.yml +1 -0
- gcf_python-1.0.0/.github/workflows/ci.yml +30 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/.github/workflows/publish.yml +5 -1
- {gcf_python-0.5.0 → gcf_python-1.0.0}/CHANGELOG.md +20 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/LICENSE +1 -1
- {gcf_python-0.5.0 → gcf_python-1.0.0}/PKG-INFO +23 -28
- {gcf_python-0.5.0 → gcf_python-1.0.0}/README.md +21 -26
- {gcf_python-0.5.0 → gcf_python-1.0.0}/pyproject.toml +2 -2
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/__init__.py +1 -1
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/decode.py +17 -7
- gcf_python-1.0.0/src/gcf/decode_generic.py +505 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/delta.py +1 -1
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/encode.py +1 -1
- gcf_python-1.0.0/src/gcf/generic.py +179 -0
- gcf_python-1.0.0/src/gcf/scalar.py +298 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/session.py +1 -1
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/stream.py +9 -9
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/stream_generic.py +7 -27
- gcf_python-1.0.0/tests/test_conformance_v2.py +105 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/test_decode.py +13 -13
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/test_encode.py +2 -2
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/test_generic.py +14 -14
- gcf_python-1.0.0/tests/test_roundtrip_v2.py +246 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/test_stream.py +3 -3
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/test_stream_generic.py +4 -4
- gcf_python-0.5.0/.github/workflows/ci.yml +0 -21
- gcf_python-0.5.0/src/gcf/decode_generic.py +0 -255
- gcf_python-0.5.0/src/gcf/generic.py +0 -156
- {gcf_python-0.5.0 → gcf_python-1.0.0}/.gitignore +0 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/cli.py +0 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/constants.py +0 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/src/gcf/types.py +0 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/__init__.py +0 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/test_delta.py +0 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/test_roundtrip.py +0 -0
- {gcf_python-0.5.0 → gcf_python-1.0.0}/tests/test_session.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
github: [blackwell-systems]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
with:
|
|
19
|
+
repository: blackwell-systems/gcf
|
|
20
|
+
path: gcf
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
- run: pip install -e ".[dev]" || pip install -e . && pip install pytest
|
|
25
|
+
- name: Unit tests
|
|
26
|
+
run: pytest tests/ -v --ignore=tests/test_conformance_v2.py --ignore=tests/test_roundtrip_v2.py
|
|
27
|
+
- name: Conformance tests (133 fixtures)
|
|
28
|
+
run: pytest tests/test_conformance_v2.py -v
|
|
29
|
+
- name: Property-based round-trip (100K random + 100K adversarial)
|
|
30
|
+
run: pytest tests/test_roundtrip_v2.py -v
|
|
@@ -8,7 +8,7 @@ jobs:
|
|
|
8
8
|
publish:
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
permissions:
|
|
11
|
-
contents:
|
|
11
|
+
contents: write
|
|
12
12
|
id-token: write
|
|
13
13
|
steps:
|
|
14
14
|
- uses: actions/checkout@v4
|
|
@@ -22,3 +22,7 @@ jobs:
|
|
|
22
22
|
env:
|
|
23
23
|
TWINE_USERNAME: __token__
|
|
24
24
|
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
|
25
|
+
- name: Create GitHub release
|
|
26
|
+
uses: softprops/action-gh-release@v2
|
|
27
|
+
with:
|
|
28
|
+
generate_release_notes: true
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.0.0 (2026-06-10)
|
|
4
|
+
|
|
5
|
+
SPEC v2.0 implementation. 126/133 conformance fixtures passing (7 skipped: session, delta, binary UTF-8, negative zero, graph encode). 40M property-based round-trips with zero failures.
|
|
6
|
+
|
|
7
|
+
### Breaking changes from v0.5.0
|
|
8
|
+
|
|
9
|
+
- `encode_generic` emits `GCF profile=generic` header
|
|
10
|
+
- `decode_generic` requires `GCF profile=` header
|
|
11
|
+
- Strings colliding with typed literals are quoted
|
|
12
|
+
- Full JSON string escaping and number grammar
|
|
13
|
+
- `-` for null, `~` for absent, `^` for nested attachments
|
|
14
|
+
- `##! summary` trailer replaces `## _summary`
|
|
15
|
+
- Graph encoder emits `profile=graph`
|
|
16
|
+
|
|
17
|
+
### New
|
|
18
|
+
|
|
19
|
+
- `scalar.py`: common scalar grammar (quoting, escaping, parsing, number formatting)
|
|
20
|
+
- Conformance test runner (133 fixtures)
|
|
21
|
+
- Property-based round-trip tests (40M verified, configurable via `GCF_ITERATIONS`)
|
|
22
|
+
|
|
3
23
|
## v0.5.0 (2026-06-06)
|
|
4
24
|
|
|
5
25
|
- `GenericStreamEncoder`: zero-buffering tabular streaming encode (begin_array/write_row/end_array/write_kv/write_section/write_inline_array)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gcf-python
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Drop-in JSON replacement for AI pipelines. 79% fewer tokens. 90.5% comprehension across 10 models. Zero dependencies.
|
|
5
5
|
Project-URL: Homepage, https://github.com/blackwell-systems/gcf-python
|
|
6
6
|
Project-URL: Documentation, https://blackwell-systems.github.io/gcf/
|
|
7
7
|
Project-URL: Specification, https://github.com/blackwell-systems/gcf
|
|
@@ -32,7 +32,7 @@ Description-Content-Type: text/markdown
|
|
|
32
32
|
|
|
33
33
|
Python implementation of [GCF](https://gcformat.com/) — the most token-efficient wire format for LLMs. A drop-in alternative to JSON and TOON for any structured data.
|
|
34
34
|
|
|
35
|
-
**79% fewer input tokens than JSON.
|
|
35
|
+
**79% fewer input tokens than JSON. 63% fewer output tokens. 90.5% average comprehension accuracy across 10 models and 3 providers (four models hit 100%). 1,300+ LLM evaluations. Zero training.**
|
|
36
36
|
|
|
37
37
|
Docs: [gcformat.com](https://gcformat.com/) · [Playground](https://gcformat.com/playground.html) · [GCF vs TOON](https://gcformat.com/guide/vs-toon.html)
|
|
38
38
|
|
|
@@ -204,33 +204,18 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
|
|
|
204
204
|
| `Session` | Thread-safe tracker for multi-call deduplication |
|
|
205
205
|
| `KIND_ABBREV` / `KIND_EXPAND` | Bidirectional kind abbreviation dicts |
|
|
206
206
|
|
|
207
|
-
##
|
|
207
|
+
## Benchmarks
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
1,300+ LLM evaluations across 10 models, 3 providers, and 51 independent test runs.
|
|
210
210
|
|
|
211
|
-
|
|
|
212
|
-
|
|
213
|
-
| **
|
|
214
|
-
|
|
|
215
|
-
|
|
|
211
|
+
| | GCF | TOON | JSON |
|
|
212
|
+
|---|---|---|---|
|
|
213
|
+
| **Comprehension** (23 runs, 10 models) | **90.5%** | 68.5% | 53.6% |
|
|
214
|
+
| **Generation** (28 runs, 9 models) | **5/5** | 1.0/5 | 5.0/5 |
|
|
215
|
+
| **Input tokens** (500 symbols) | **11,090** | 16,378 | 53,341 |
|
|
216
|
+
| **Output tokens** (100 symbols) | **5,976** | 8,937 | 16,121 |
|
|
216
217
|
|
|
217
|
-
GCF
|
|
218
|
-
|
|
219
|
-
Reproduce: `git clone https://github.com/blackwell-systems/gcf-go && cd gcf-go/eval && GOWORK=off go test -run TestComprehension -v -timeout 0`
|
|
220
|
-
|
|
221
|
-
## Token Efficiency (TOON's Own Benchmark)
|
|
222
|
-
|
|
223
|
-
Running [TOON's benchmark harness](https://github.com/blackwell-systems/toon/tree/gcf-comparison) with GCF inserted (their datasets, their tokenizer):
|
|
224
|
-
|
|
225
|
-
| Track | GCF | TOON | Result |
|
|
226
|
-
|-------|-----|------|--------|
|
|
227
|
-
| Mixed-structure (nested, semi-uniform) | 170,367 | 227,896 | **GCF 34% smaller** |
|
|
228
|
-
| Flat-only (tabular) | 66,029 | 67,837 | **GCF 3% smaller** |
|
|
229
|
-
| Semi-uniform event logs | 108,158 | 154,032 | **GCF 42% smaller** |
|
|
230
|
-
|
|
231
|
-
GCF wins all 6 datasets. On semi-uniform data (the most common real-world pattern), GCF uses 42% fewer tokens than TOON.
|
|
232
|
-
|
|
233
|
-
Reproduce: `git clone https://github.com/blackwell-systems/toon && cd toon && git checkout gcf-comparison && cd benchmarks && pnpm install && pnpm benchmark:tokens`
|
|
218
|
+
GCF wins all 6 datasets on [TOON's own benchmark](https://github.com/blackwell-systems/toon/tree/gcf-comparison). Full results: [gcformat.com/guide/benchmarks](https://gcformat.com/guide/benchmarks.html)
|
|
234
219
|
|
|
235
220
|
## Links
|
|
236
221
|
|
|
@@ -243,6 +228,16 @@ Reproduce: `git clone https://github.com/blackwell-systems/toon && cd toon && gi
|
|
|
243
228
|
- [GCF vs TOON](https://gcformat.com/guide/vs-toon.html)
|
|
244
229
|
- [TOON benchmark fork](https://github.com/blackwell-systems/toon/tree/gcf-comparison)
|
|
245
230
|
|
|
231
|
+
|
|
232
|
+
<details>
|
|
233
|
+
<summary>More links</summary>
|
|
234
|
+
|
|
235
|
+
- [betterthanjson.com](https://betterthanjson.com)
|
|
236
|
+
- [jsonalternative.com](https://jsonalternative.com)
|
|
237
|
+
- [betterthantoon.com](https://betterthantoon.com)
|
|
238
|
+
|
|
239
|
+
</details>
|
|
240
|
+
|
|
246
241
|
## License
|
|
247
242
|
|
|
248
|
-
MIT
|
|
243
|
+
MIT - [Dayna Blackwell](https://github.com/blackwell-systems)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
Python implementation of [GCF](https://gcformat.com/) — the most token-efficient wire format for LLMs. A drop-in alternative to JSON and TOON for any structured data.
|
|
9
9
|
|
|
10
|
-
**79% fewer input tokens than JSON.
|
|
10
|
+
**79% fewer input tokens than JSON. 63% fewer output tokens. 90.5% average comprehension accuracy across 10 models and 3 providers (four models hit 100%). 1,300+ LLM evaluations. Zero training.**
|
|
11
11
|
|
|
12
12
|
Docs: [gcformat.com](https://gcformat.com/) · [Playground](https://gcformat.com/playground.html) · [GCF vs TOON](https://gcformat.com/guide/vs-toon.html)
|
|
13
13
|
|
|
@@ -179,33 +179,18 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
|
|
|
179
179
|
| `Session` | Thread-safe tracker for multi-call deduplication |
|
|
180
180
|
| `KIND_ABBREV` / `KIND_EXPAND` | Bidirectional kind abbreviation dicts |
|
|
181
181
|
|
|
182
|
-
##
|
|
182
|
+
## Benchmarks
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
1,300+ LLM evaluations across 10 models, 3 providers, and 51 independent test runs.
|
|
185
185
|
|
|
186
|
-
|
|
|
187
|
-
|
|
188
|
-
| **
|
|
189
|
-
|
|
|
190
|
-
|
|
|
186
|
+
| | GCF | TOON | JSON |
|
|
187
|
+
|---|---|---|---|
|
|
188
|
+
| **Comprehension** (23 runs, 10 models) | **90.5%** | 68.5% | 53.6% |
|
|
189
|
+
| **Generation** (28 runs, 9 models) | **5/5** | 1.0/5 | 5.0/5 |
|
|
190
|
+
| **Input tokens** (500 symbols) | **11,090** | 16,378 | 53,341 |
|
|
191
|
+
| **Output tokens** (100 symbols) | **5,976** | 8,937 | 16,121 |
|
|
191
192
|
|
|
192
|
-
GCF
|
|
193
|
-
|
|
194
|
-
Reproduce: `git clone https://github.com/blackwell-systems/gcf-go && cd gcf-go/eval && GOWORK=off go test -run TestComprehension -v -timeout 0`
|
|
195
|
-
|
|
196
|
-
## Token Efficiency (TOON's Own Benchmark)
|
|
197
|
-
|
|
198
|
-
Running [TOON's benchmark harness](https://github.com/blackwell-systems/toon/tree/gcf-comparison) with GCF inserted (their datasets, their tokenizer):
|
|
199
|
-
|
|
200
|
-
| Track | GCF | TOON | Result |
|
|
201
|
-
|-------|-----|------|--------|
|
|
202
|
-
| Mixed-structure (nested, semi-uniform) | 170,367 | 227,896 | **GCF 34% smaller** |
|
|
203
|
-
| Flat-only (tabular) | 66,029 | 67,837 | **GCF 3% smaller** |
|
|
204
|
-
| Semi-uniform event logs | 108,158 | 154,032 | **GCF 42% smaller** |
|
|
205
|
-
|
|
206
|
-
GCF wins all 6 datasets. On semi-uniform data (the most common real-world pattern), GCF uses 42% fewer tokens than TOON.
|
|
207
|
-
|
|
208
|
-
Reproduce: `git clone https://github.com/blackwell-systems/toon && cd toon && git checkout gcf-comparison && cd benchmarks && pnpm install && pnpm benchmark:tokens`
|
|
193
|
+
GCF wins all 6 datasets on [TOON's own benchmark](https://github.com/blackwell-systems/toon/tree/gcf-comparison). Full results: [gcformat.com/guide/benchmarks](https://gcformat.com/guide/benchmarks.html)
|
|
209
194
|
|
|
210
195
|
## Links
|
|
211
196
|
|
|
@@ -218,6 +203,16 @@ Reproduce: `git clone https://github.com/blackwell-systems/toon && cd toon && gi
|
|
|
218
203
|
- [GCF vs TOON](https://gcformat.com/guide/vs-toon.html)
|
|
219
204
|
- [TOON benchmark fork](https://github.com/blackwell-systems/toon/tree/gcf-comparison)
|
|
220
205
|
|
|
206
|
+
|
|
207
|
+
<details>
|
|
208
|
+
<summary>More links</summary>
|
|
209
|
+
|
|
210
|
+
- [betterthanjson.com](https://betterthanjson.com)
|
|
211
|
+
- [jsonalternative.com](https://jsonalternative.com)
|
|
212
|
+
- [betterthantoon.com](https://betterthantoon.com)
|
|
213
|
+
|
|
214
|
+
</details>
|
|
215
|
+
|
|
221
216
|
## License
|
|
222
217
|
|
|
223
|
-
MIT
|
|
218
|
+
MIT - [Dayna Blackwell](https://github.com/blackwell-systems)
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gcf-python"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Drop-in JSON replacement for AI pipelines. 79% fewer tokens. 90.5% comprehension across 10 models. Zero dependencies."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
11
11
|
requires-python = ">=3.9"
|
|
@@ -35,7 +35,11 @@ def decode(input_text: str) -> Payload:
|
|
|
35
35
|
_parse_header(header[4:], p)
|
|
36
36
|
|
|
37
37
|
if not p.tool:
|
|
38
|
-
raise DecodeError("header missing required 'tool' field")
|
|
38
|
+
raise DecodeError("missing_tool: header missing required 'tool' field")
|
|
39
|
+
|
|
40
|
+
# Detect delta mode.
|
|
41
|
+
is_delta = "delta=true" in header
|
|
42
|
+
valid_delta_sections = {"removed", "added", "edges_removed", "edges_added"}
|
|
39
43
|
|
|
40
44
|
# Parse body: symbols and edges.
|
|
41
45
|
symbols: list[Symbol] = []
|
|
@@ -48,6 +52,10 @@ def decode(input_text: str) -> Payload:
|
|
|
48
52
|
if not line:
|
|
49
53
|
continue
|
|
50
54
|
|
|
55
|
+
# Skip ##! summary trailer.
|
|
56
|
+
if line.startswith("##! "):
|
|
57
|
+
continue
|
|
58
|
+
|
|
51
59
|
# Group header.
|
|
52
60
|
if line.startswith("## "):
|
|
53
61
|
group = line[3:]
|
|
@@ -55,6 +63,8 @@ def decode(input_text: str) -> Payload:
|
|
|
55
63
|
bracket_idx = group.find(" [")
|
|
56
64
|
if bracket_idx >= 0:
|
|
57
65
|
group = group[:bracket_idx]
|
|
66
|
+
if is_delta and group not in valid_delta_sections:
|
|
67
|
+
raise DecodeError(f"malformed_delta: invalid delta section {group!r}")
|
|
58
68
|
in_edges = group == "edges"
|
|
59
69
|
if not in_edges:
|
|
60
70
|
if group == "targets":
|
|
@@ -113,19 +123,19 @@ def _parse_header(fields: str, p: Payload) -> None:
|
|
|
113
123
|
def _parse_symbol_line(line: str, distance: int) -> tuple[Symbol, int]:
|
|
114
124
|
"""Parse a symbol line into a Symbol and its local ID."""
|
|
115
125
|
if not line.startswith("@"):
|
|
116
|
-
raise DecodeError(f"expected symbol line starting with @, got {line!r}")
|
|
126
|
+
raise DecodeError(f"invalid_node_line: expected symbol line starting with @, got {line!r}")
|
|
117
127
|
|
|
118
128
|
parts = line.split()
|
|
119
129
|
if len(parts) < 5:
|
|
120
130
|
raise DecodeError(
|
|
121
|
-
f"symbol line needs at least 5 fields, got {len(parts)} in {line!r}"
|
|
131
|
+
f"invalid_node_line: symbol line needs at least 5 fields, got {len(parts)} in {line!r}"
|
|
122
132
|
)
|
|
123
133
|
|
|
124
134
|
id_str = parts[0][1:] # strip @
|
|
125
135
|
try:
|
|
126
136
|
sym_id = int(id_str)
|
|
127
137
|
except ValueError as e:
|
|
128
|
-
raise DecodeError(f"invalid symbol id {id_str!r}: {e}") from e
|
|
138
|
+
raise DecodeError(f"invalid_symbol_id: invalid symbol id {id_str!r}: {e}") from e
|
|
129
139
|
|
|
130
140
|
kind = parts[1]
|
|
131
141
|
kind = KIND_EXPAND.get(kind, kind)
|
|
@@ -135,7 +145,7 @@ def _parse_symbol_line(line: str, distance: int) -> tuple[Symbol, int]:
|
|
|
135
145
|
try:
|
|
136
146
|
score = float(parts[3])
|
|
137
147
|
except ValueError as e:
|
|
138
|
-
raise DecodeError(f"invalid score {parts[3]!r}: {e}") from e
|
|
148
|
+
raise DecodeError(f"invalid_score: invalid score {parts[3]!r}: {e}") from e
|
|
139
149
|
|
|
140
150
|
provenance = parts[4]
|
|
141
151
|
|
|
@@ -157,7 +167,7 @@ def _parse_edge_line(line: str, sym_by_id: dict[int, Symbol]) -> Edge:
|
|
|
157
167
|
ref = parts[0]
|
|
158
168
|
lt_idx = ref.find("<")
|
|
159
169
|
if lt_idx < 0:
|
|
160
|
-
raise DecodeError(f"edge line missing '<' separator in {ref!r}")
|
|
170
|
+
raise DecodeError(f"invalid_edge_syntax: edge line missing '<' separator in {ref!r}")
|
|
161
171
|
|
|
162
172
|
target_id_str = ref[1:lt_idx] # strip leading @
|
|
163
173
|
source_id_str = ref[lt_idx + 2:] # strip <@
|
|
@@ -176,7 +186,7 @@ def _parse_edge_line(line: str, sym_by_id: dict[int, Symbol]) -> Edge:
|
|
|
176
186
|
source_sym = sym_by_id.get(source_id)
|
|
177
187
|
if target_sym is None or source_sym is None:
|
|
178
188
|
raise DecodeError(
|
|
179
|
-
f"edge references unknown symbol id(s): target={target_id} source={source_id}"
|
|
189
|
+
f"unknown_edge_reference: edge references unknown symbol id(s): target={target_id} source={source_id}"
|
|
180
190
|
)
|
|
181
191
|
|
|
182
192
|
edge_type = parts[1]
|