tiergraph 0.1.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.
- tiergraph-0.1.0/.github/workflows/ci.yml +87 -0
- tiergraph-0.1.0/.github/workflows/publish.yml +55 -0
- tiergraph-0.1.0/.gitignore +13 -0
- tiergraph-0.1.0/.pre-commit-config.yaml +32 -0
- tiergraph-0.1.0/CHANGELOG.md +21 -0
- tiergraph-0.1.0/CONTRIBUTING.md +75 -0
- tiergraph-0.1.0/LICENSE +24 -0
- tiergraph-0.1.0/Makefile +59 -0
- tiergraph-0.1.0/PKG-INFO +160 -0
- tiergraph-0.1.0/README.md +127 -0
- tiergraph-0.1.0/RELEASING.md +95 -0
- tiergraph-0.1.0/SECURITY.md +27 -0
- tiergraph-0.1.0/docs/README.md +39 -0
- tiergraph-0.1.0/docs/concepts.md +138 -0
- tiergraph-0.1.0/docs/contributing-docs.md +13 -0
- tiergraph-0.1.0/docs/format.md +43 -0
- tiergraph-0.1.0/docs/getting-started.md +224 -0
- tiergraph-0.1.0/docs/guide/construction.md +142 -0
- tiergraph-0.1.0/docs/guide/folding.md +218 -0
- tiergraph-0.1.0/docs/guide/profiles.md +139 -0
- tiergraph-0.1.0/docs/guide/recognize-and-act.md +234 -0
- tiergraph-0.1.0/docs/guide/selection-and-traversal.md +219 -0
- tiergraph-0.1.0/docs/guide/serialization.md +146 -0
- tiergraph-0.1.0/docs/guide/span-views.md +21 -0
- tiergraph-0.1.0/docs/guide/timing.md +144 -0
- tiergraph-0.1.0/docs/manifest.json +74 -0
- tiergraph-0.1.0/docs/reference/api.md +3969 -0
- tiergraph-0.1.0/docs/reference/cli.md +436 -0
- tiergraph-0.1.0/examples/__init__.py +1 -0
- tiergraph-0.1.0/examples/caption_alignment.py +64 -0
- tiergraph-0.1.0/examples/critical_path.py +101 -0
- tiergraph-0.1.0/examples/json_document.py +39 -0
- tiergraph-0.1.0/examples/mix_paths.py +511 -0
- tiergraph-0.1.0/examples/mixing.py +208 -0
- tiergraph-0.1.0/examples/text_segmentation.py +111 -0
- tiergraph-0.1.0/pyproject.toml +77 -0
- tiergraph-0.1.0/schema/tiergraph.schema.json +893 -0
- tiergraph-0.1.0/schema/tiergraph.schema.sha256 +5 -0
- tiergraph-0.1.0/scripts/__init__.py +1 -0
- tiergraph-0.1.0/scripts/check_documented.py +46 -0
- tiergraph-0.1.0/scripts/check_tracked_clean.py +70 -0
- tiergraph-0.1.0/scripts/generate_docs.py +467 -0
- tiergraph-0.1.0/scripts/generate_schema.py +100 -0
- tiergraph-0.1.0/src/tiergraph/__init__.py +325 -0
- tiergraph-0.1.0/src/tiergraph/__main__.py +6 -0
- tiergraph-0.1.0/src/tiergraph/action.py +492 -0
- tiergraph-0.1.0/src/tiergraph/build.py +838 -0
- tiergraph-0.1.0/src/tiergraph/cli/__init__.py +804 -0
- tiergraph-0.1.0/src/tiergraph/clock.py +680 -0
- tiergraph-0.1.0/src/tiergraph/core.py +1586 -0
- tiergraph-0.1.0/src/tiergraph/fold.py +831 -0
- tiergraph-0.1.0/src/tiergraph/grammar.py +1286 -0
- tiergraph-0.1.0/src/tiergraph/inspect.py +41 -0
- tiergraph-0.1.0/src/tiergraph/machine.py +1417 -0
- tiergraph-0.1.0/src/tiergraph/machine_codec.py +106 -0
- tiergraph-0.1.0/src/tiergraph/path.py +497 -0
- tiergraph-0.1.0/src/tiergraph/py.typed +0 -0
- tiergraph-0.1.0/src/tiergraph/root.py +222 -0
- tiergraph-0.1.0/src/tiergraph/schema.py +537 -0
- tiergraph-0.1.0/src/tiergraph/selection.py +364 -0
- tiergraph-0.1.0/src/tiergraph/selection_query.py +277 -0
- tiergraph-0.1.0/src/tiergraph/semiring.py +660 -0
- tiergraph-0.1.0/src/tiergraph/spanview.py +491 -0
- tiergraph-0.1.0/src/tiergraph/traversal.py +634 -0
- tiergraph-0.1.0/src/tiergraph/value.py +481 -0
- tiergraph-0.1.0/src/tiergraph/wire.py +626 -0
- tiergraph-0.1.0/src/tiergraph_dot/__init__.py +979 -0
- tiergraph-0.1.0/src/tiergraph_dot/py.typed +0 -0
- tiergraph-0.1.0/tests/__init__.py +1 -0
- tiergraph-0.1.0/tests/conformance/__init__.py +1 -0
- tiergraph-0.1.0/tests/conformance/action.py +89 -0
- tiergraph-0.1.0/tests/conformance/declared_schema_codec_divergences.py +55 -0
- tiergraph-0.1.0/tests/conformance/fold.py +302 -0
- tiergraph-0.1.0/tests/conformance/kernel.py +237 -0
- tiergraph-0.1.0/tests/conformance/machine.py +570 -0
- tiergraph-0.1.0/tests/conformance/recognition.py +66 -0
- tiergraph-0.1.0/tests/conformance/schema.py +33 -0
- tiergraph-0.1.0/tests/conformance/schema_codec.py +327 -0
- tiergraph-0.1.0/tests/conformance/selection.py +323 -0
- tiergraph-0.1.0/tests/conformance/traversal.py +248 -0
- tiergraph-0.1.0/tests/conformance/wire.py +74 -0
- tiergraph-0.1.0/tests/semiring_laws.py +175 -0
- tiergraph-0.1.0/tests/test_action.py +472 -0
- tiergraph-0.1.0/tests/test_alignment_witness.py +359 -0
- tiergraph-0.1.0/tests/test_alternation_witness.py +566 -0
- tiergraph-0.1.0/tests/test_boundary_witness.py +247 -0
- tiergraph-0.1.0/tests/test_build.py +785 -0
- tiergraph-0.1.0/tests/test_cli.py +1761 -0
- tiergraph-0.1.0/tests/test_clock.py +1026 -0
- tiergraph-0.1.0/tests/test_core.py +1200 -0
- tiergraph-0.1.0/tests/test_docs.py +308 -0
- tiergraph-0.1.0/tests/test_dot.py +2009 -0
- tiergraph-0.1.0/tests/test_examples.py +43 -0
- tiergraph-0.1.0/tests/test_external_reference_witness.py +361 -0
- tiergraph-0.1.0/tests/test_fold.py +762 -0
- tiergraph-0.1.0/tests/test_fold_witness.py +416 -0
- tiergraph-0.1.0/tests/test_grammar.py +709 -0
- tiergraph-0.1.0/tests/test_inspect.py +50 -0
- tiergraph-0.1.0/tests/test_machine.py +1016 -0
- tiergraph-0.1.0/tests/test_machine_codec.py +173 -0
- tiergraph-0.1.0/tests/test_mix_paths.py +426 -0
- tiergraph-0.1.0/tests/test_ordered_containment.py +384 -0
- tiergraph-0.1.0/tests/test_ordered_polyadic_traversal.py +293 -0
- tiergraph-0.1.0/tests/test_package.py +35 -0
- tiergraph-0.1.0/tests/test_path.py +381 -0
- tiergraph-0.1.0/tests/test_path_alternation.py +373 -0
- tiergraph-0.1.0/tests/test_polyadic_relations.py +430 -0
- tiergraph-0.1.0/tests/test_publishability_guards.py +71 -0
- tiergraph-0.1.0/tests/test_root.py +383 -0
- tiergraph-0.1.0/tests/test_schema.py +457 -0
- tiergraph-0.1.0/tests/test_schema_codec_conformance.py +259 -0
- tiergraph-0.1.0/tests/test_selection.py +164 -0
- tiergraph-0.1.0/tests/test_semiring.py +421 -0
- tiergraph-0.1.0/tests/test_semiring_law_discrimination.py +208 -0
- tiergraph-0.1.0/tests/test_spanview.py +538 -0
- tiergraph-0.1.0/tests/test_text_domain.py +244 -0
- tiergraph-0.1.0/tests/test_traversal.py +52 -0
- tiergraph-0.1.0/tests/test_value.py +441 -0
- tiergraph-0.1.0/tests/test_wire.py +784 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test-python-313:
|
|
18
|
+
name: test (Python 3.13)
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v5
|
|
22
|
+
# Only run the 3.13 compatibility suite when code changes; a docs- or
|
|
23
|
+
# metadata-only change cannot affect it, and the job still reports success
|
|
24
|
+
# so a required check does not hang.
|
|
25
|
+
- uses: dorny/paths-filter@v3
|
|
26
|
+
id: changes
|
|
27
|
+
with:
|
|
28
|
+
filters: |
|
|
29
|
+
code:
|
|
30
|
+
- 'src/**'
|
|
31
|
+
- 'tests/**'
|
|
32
|
+
- 'examples/**'
|
|
33
|
+
- 'scripts/**'
|
|
34
|
+
- 'pyproject.toml'
|
|
35
|
+
- '.github/workflows/ci.yml'
|
|
36
|
+
- if: steps.changes.outputs.code == 'true'
|
|
37
|
+
uses: actions/setup-python@v6
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.13"
|
|
40
|
+
cache: pip
|
|
41
|
+
cache-dependency-path: pyproject.toml
|
|
42
|
+
- if: steps.changes.outputs.code == 'true'
|
|
43
|
+
run: python -m pip install --upgrade pip
|
|
44
|
+
- if: steps.changes.outputs.code == 'true'
|
|
45
|
+
run: python -m pip install -e ".[test]"
|
|
46
|
+
# The documentation gate type-checks doc code fences with mypy (a dev-tooling
|
|
47
|
+
# concern pinned to the 3.12 environment) and is covered by the full make check job.
|
|
48
|
+
- if: steps.changes.outputs.code == 'true'
|
|
49
|
+
run: python -m pytest --deselect tests/test_docs.py::test_documentation_gate_is_current
|
|
50
|
+
- if: steps.changes.outputs.code != 'true'
|
|
51
|
+
run: echo "No code changed; skipping the 3.13 compatibility suite."
|
|
52
|
+
|
|
53
|
+
check:
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v5
|
|
57
|
+
# The full gate runs whenever code or gate-checked docs change. A change
|
|
58
|
+
# confined to inert files -- the release workflow, release notes, the
|
|
59
|
+
# license -- skips it, and the job still reports success so the required
|
|
60
|
+
# check does not hang. Anything under src, tests, docs, examples, scripts,
|
|
61
|
+
# or the build files keeps docs currency and code gated.
|
|
62
|
+
- uses: dorny/paths-filter@v3
|
|
63
|
+
id: changes
|
|
64
|
+
with:
|
|
65
|
+
filters: |
|
|
66
|
+
gated:
|
|
67
|
+
- 'src/**'
|
|
68
|
+
- 'tests/**'
|
|
69
|
+
- 'examples/**'
|
|
70
|
+
- 'scripts/**'
|
|
71
|
+
- 'docs/**'
|
|
72
|
+
- 'pyproject.toml'
|
|
73
|
+
- 'Makefile'
|
|
74
|
+
- 'README.md'
|
|
75
|
+
- '.github/workflows/ci.yml'
|
|
76
|
+
- if: steps.changes.outputs.gated == 'true'
|
|
77
|
+
uses: actions/setup-python@v6
|
|
78
|
+
with:
|
|
79
|
+
python-version: "3.13"
|
|
80
|
+
cache: pip
|
|
81
|
+
cache-dependency-path: pyproject.toml
|
|
82
|
+
# make check builds its own environment, so CI runs the same path as a
|
|
83
|
+
# developer rather than a parallel one that can drift.
|
|
84
|
+
- if: steps.changes.outputs.gated == 'true'
|
|
85
|
+
run: make check
|
|
86
|
+
- if: steps.changes.outputs.gated != 'true'
|
|
87
|
+
run: echo "Only inert files changed (workflow or release notes); skipping the full gate."
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
# Build once, then publish via PyPI Trusted Publishing (OIDC) -- no API tokens.
|
|
4
|
+
# Cut a GitHub Release (tag vX.Y.Z) to publish to PyPI.
|
|
5
|
+
#
|
|
6
|
+
# One-time setup (see RELEASING.md):
|
|
7
|
+
# - PyPI: add a Trusted Publisher (project tiergraph, this repo, workflow
|
|
8
|
+
# publish.yml, environment "pypi").
|
|
9
|
+
# - GitHub: create environment "pypi" (Settings > Environments).
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
release:
|
|
13
|
+
types: [published]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build:
|
|
20
|
+
name: build sdist + wheel
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-python@v7
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
- run: python -m pip install --upgrade pip build
|
|
28
|
+
- run: python -m build
|
|
29
|
+
- name: Verify version matches release tag
|
|
30
|
+
env:
|
|
31
|
+
TAG: ${{ github.event.release.tag_name }}
|
|
32
|
+
run: |
|
|
33
|
+
VERSION=$(PYTHONPATH=src python -c "import tiergraph; print(tiergraph.__version__)")
|
|
34
|
+
echo "tiergraph.__version__=$VERSION release tag=$TAG"
|
|
35
|
+
test "$VERSION" = "${TAG#v}"
|
|
36
|
+
- uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: dist
|
|
39
|
+
path: dist/
|
|
40
|
+
|
|
41
|
+
publish-pypi:
|
|
42
|
+
name: publish to PyPI
|
|
43
|
+
needs: build
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
environment:
|
|
46
|
+
name: pypi
|
|
47
|
+
url: https://pypi.org/p/tiergraph
|
|
48
|
+
permissions:
|
|
49
|
+
id-token: write
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/download-artifact@v4
|
|
52
|
+
with:
|
|
53
|
+
name: dist
|
|
54
|
+
path: dist/
|
|
55
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
minimum_pre_commit_version: "3.0.0"
|
|
2
|
+
|
|
3
|
+
repos:
|
|
4
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
+
rev: v6.0.0
|
|
6
|
+
hooks:
|
|
7
|
+
- id: trailing-whitespace
|
|
8
|
+
- id: end-of-file-fixer
|
|
9
|
+
- id: check-yaml
|
|
10
|
+
- id: check-toml
|
|
11
|
+
- id: check-merge-conflict
|
|
12
|
+
- id: check-added-large-files
|
|
13
|
+
|
|
14
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
15
|
+
rev: v0.16.1
|
|
16
|
+
hooks:
|
|
17
|
+
- id: ruff-check
|
|
18
|
+
args: ["--fix"]
|
|
19
|
+
- id: ruff-format
|
|
20
|
+
|
|
21
|
+
- repo: local
|
|
22
|
+
hooks:
|
|
23
|
+
- id: tracked-clean
|
|
24
|
+
name: tracked files carry nothing local
|
|
25
|
+
entry: python scripts/check_tracked_clean.py
|
|
26
|
+
language: system
|
|
27
|
+
pass_filenames: false
|
|
28
|
+
- id: documented
|
|
29
|
+
name: public names carry a docstring
|
|
30
|
+
entry: python scripts/check_documented.py
|
|
31
|
+
language: system
|
|
32
|
+
pass_filenames: false
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-08-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Immutable ordered-tier graphs with declared namespaces, typed attributes, item and boundary references, and simple, bipartite, and polyadic relations.
|
|
13
|
+
- A checked opcode `Program` and build machine for declaring and populating graphs, with bounded repetition, execution traces, and unrolling to an immutable `Graph`.
|
|
14
|
+
- Semiring folds over finite dependency DAGs, including exact min- and max-plus carriers and the `PATH` semiring's tied best-path provenance and capped n-best ranked witnesses.
|
|
15
|
+
- Clock profiles for structural refinement and physical timing, including `ClockProfile.from_position_values`, optional shared-boundary collapse, and the `is_structural` capability flag.
|
|
16
|
+
- Deterministic span projections through `tiergraph.spanview`, with text, JSON, JSON Lines, and HTML emitters, plus `tiergraph_dot.dumps_spans` visualization.
|
|
17
|
+
- Deterministic Graphviz DOT rendering through `tiergraph_dot.dumps`, including `DotPresentation` hooks and structural-clock occupied-spine placement and relation rendering.
|
|
18
|
+
- TG-PATH canonical addressing for structural and durable items and boundaries, profile-owned alternatives, kind checks, and typed refusals with offender details.
|
|
19
|
+
- Canonical selection, bounded bipartite walks, ordered polyadic traversal, and ordered containment queries that preserve declared incidence and child order where applicable.
|
|
20
|
+
|
|
21
|
+
[0.1.0]: https://github.com/lenzo-ka/tiergraph/releases/tag/v0.1.0
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Contributing to tiergraph
|
|
2
|
+
|
|
3
|
+
Thank you for contributing to tiergraph. This project is alpha software, so a
|
|
4
|
+
small, well-tested change is especially valuable.
|
|
5
|
+
|
|
6
|
+
## Set up a development environment
|
|
7
|
+
|
|
8
|
+
tiergraph requires Python 3.12 or later. Development is pinned to Python 3.12,
|
|
9
|
+
the supported floor, so newer Python features do not enter the codebase
|
|
10
|
+
accidentally. From the repository root, create the isolated development
|
|
11
|
+
environment and install the project with its development dependencies:
|
|
12
|
+
|
|
13
|
+
```console
|
|
14
|
+
make venv
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
By default, this uses `python3.12` and creates `.venv`. You can override the
|
|
18
|
+
interpreter with `PYTHON=/path/to/python3.12` or the environment directory with
|
|
19
|
+
`VENV=/path/to/venv`.
|
|
20
|
+
|
|
21
|
+
## Check a change
|
|
22
|
+
|
|
23
|
+
Run the same full gate used by CI:
|
|
24
|
+
|
|
25
|
+
```console
|
|
26
|
+
make check
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The gate runs Ruff linting and formatting checks, strict mypy checks, pytest,
|
|
30
|
+
the test suite in separate processes with hash seeds 0, 12345, and 999, JSON
|
|
31
|
+
Schema currency checks, documentation currency checks, the tracked-file hygiene
|
|
32
|
+
check, and the public-docstring check. Coverage is measured only for the shipped
|
|
33
|
+
`tiergraph` and `tiergraph_dot` packages and must remain at 100% branch coverage.
|
|
34
|
+
|
|
35
|
+
The repository also provides a pre-commit configuration. After installing
|
|
36
|
+
`pre-commit` separately, enable it in your checkout with:
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
pre-commit install
|
|
40
|
+
pre-commit run --all-files
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Those hooks apply basic file checks and Ruff, then run the tracked-file hygiene
|
|
44
|
+
and public-docstring checks. They complement rather than replace `make check`.
|
|
45
|
+
|
|
46
|
+
## Documentation
|
|
47
|
+
|
|
48
|
+
Reader documentation lives in `README.md` and `docs/`. Every page under `docs/`
|
|
49
|
+
must be registered in `docs/manifest.json`. Generated sections and references
|
|
50
|
+
must be refreshed with `make docs`; `make docs-check` (implemented as
|
|
51
|
+
`scripts/generate_docs.py --check`) verifies that committed output matches a
|
|
52
|
+
fresh deterministic render. See [Contributing documentation](docs/contributing-docs.md)
|
|
53
|
+
for the rules governing pages, generated output, executable examples, and export
|
|
54
|
+
lists.
|
|
55
|
+
|
|
56
|
+
## What is accepted
|
|
57
|
+
|
|
58
|
+
Changes should keep `make check` green, use US English, contain no AI or tool
|
|
59
|
+
attribution, and preserve compatibility through additive changes where possible.
|
|
60
|
+
Because the project is pre-1.0, an incompatible change may still be necessary;
|
|
61
|
+
make its effect explicit and keep it as narrow as practical. See the
|
|
62
|
+
[stability policy](README.md#stability).
|
|
63
|
+
|
|
64
|
+
## Releases
|
|
65
|
+
|
|
66
|
+
Releases are a maintainer operation. The package version has a single source of
|
|
67
|
+
truth in `src/tiergraph/__init__.py`. Before release, maintainers run the full
|
|
68
|
+
gate, build the distribution, verify the import reports the intended version,
|
|
69
|
+
and wait for CI to pass. A GitHub Release whose `vX.Y.Z` tag matches the package
|
|
70
|
+
version triggers the publish workflow; it builds the sdist and wheel and uploads
|
|
71
|
+
them to PyPI through trusted publishing. PyPI releases cannot be overwritten.
|
|
72
|
+
|
|
73
|
+
The complete operator checklist, including initial trusted-publisher setup,
|
|
74
|
+
artifact checks, tagging, publication, and verification, is in
|
|
75
|
+
[RELEASING.md](RELEASING.md).
|
tiergraph-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kevin Lenzo
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
19
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
20
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
21
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
22
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
23
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
24
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
tiergraph-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
VENV ?= .venv
|
|
2
|
+
# Pin development to the supported floor so newer-only features cannot slip in.
|
|
3
|
+
PYTHON ?= python3.12
|
|
4
|
+
VENV_PYTHON := $(VENV)/bin/python
|
|
5
|
+
|
|
6
|
+
.PHONY: venv lint format-check types test determinism-seed determinism schema schema-check docs docs-check tracked-clean documented check
|
|
7
|
+
|
|
8
|
+
# Development happens in an isolated environment: a shared interpreter drags in
|
|
9
|
+
# packages this project does not depend on, and they surface as type errors in
|
|
10
|
+
# other people's stubs.
|
|
11
|
+
venv: $(VENV)/bin/python
|
|
12
|
+
|
|
13
|
+
$(VENV)/bin/python:
|
|
14
|
+
@$(PYTHON) -m venv $(VENV)
|
|
15
|
+
@$(VENV)/bin/pip install --quiet --upgrade pip
|
|
16
|
+
@$(VENV)/bin/pip install --quiet -e ".[dev]"
|
|
17
|
+
|
|
18
|
+
lint:
|
|
19
|
+
@$(VENV_PYTHON) -m ruff check .
|
|
20
|
+
|
|
21
|
+
format-check:
|
|
22
|
+
@$(VENV_PYTHON) -m ruff format --check .
|
|
23
|
+
|
|
24
|
+
types:
|
|
25
|
+
@$(VENV_PYTHON) -m mypy
|
|
26
|
+
|
|
27
|
+
test:
|
|
28
|
+
@$(VENV_PYTHON) -m pytest --cov=tiergraph --cov=tiergraph_dot --cov-report=term-missing
|
|
29
|
+
|
|
30
|
+
# Separate processes: interpreter hash state is fixed at startup and cannot be
|
|
31
|
+
# changed honestly inside one run.
|
|
32
|
+
determinism-seed:
|
|
33
|
+
@test -n "$(HASH_SEED)" || (echo "HASH_SEED is required" >&2; exit 2)
|
|
34
|
+
@PYTHONHASHSEED=$(HASH_SEED) $(VENV_PYTHON) -m pytest
|
|
35
|
+
|
|
36
|
+
determinism:
|
|
37
|
+
@for seed in 0 12345 999; do \
|
|
38
|
+
$(MAKE) --no-print-directory determinism-seed HASH_SEED=$$seed || exit $$?; \
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
tracked-clean:
|
|
42
|
+
@$(VENV_PYTHON) scripts/check_tracked_clean.py
|
|
43
|
+
|
|
44
|
+
documented:
|
|
45
|
+
@$(VENV_PYTHON) scripts/check_documented.py
|
|
46
|
+
|
|
47
|
+
schema:
|
|
48
|
+
@$(VENV_PYTHON) scripts/generate_schema.py
|
|
49
|
+
|
|
50
|
+
schema-check:
|
|
51
|
+
@$(VENV_PYTHON) scripts/generate_schema.py --check
|
|
52
|
+
|
|
53
|
+
docs:
|
|
54
|
+
@$(VENV_PYTHON) scripts/generate_docs.py
|
|
55
|
+
|
|
56
|
+
docs-check:
|
|
57
|
+
@$(VENV_PYTHON) scripts/generate_docs.py --check
|
|
58
|
+
|
|
59
|
+
check: venv lint format-check types test determinism schema-check docs-check tracked-clean documented
|
tiergraph-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: tiergraph
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Ordered tiers, declared relations, and an algebra over them
|
|
5
|
+
Project-URL: Homepage, https://github.com/lenzo-ka/tiergraph
|
|
6
|
+
Project-URL: Repository, https://github.com/lenzo-ka/tiergraph
|
|
7
|
+
Author: Kevin Lenzo
|
|
8
|
+
License-Expression: BSD-2-Clause
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Typing :: Typed
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: hatchling>=1.27; extra == 'dev'
|
|
17
|
+
Requires-Dist: hypothesis>=6.100; extra == 'dev'
|
|
18
|
+
Requires-Dist: jsonschema>=4.26; extra == 'dev'
|
|
19
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
20
|
+
Requires-Dist: pydantic>=2.9; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: ruff>=0.16; extra == 'dev'
|
|
24
|
+
Provides-Extra: lint
|
|
25
|
+
Requires-Dist: mypy>=1.11; extra == 'lint'
|
|
26
|
+
Requires-Dist: ruff>=0.16; extra == 'lint'
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: hypothesis>=6.100; extra == 'test'
|
|
29
|
+
Requires-Dist: jsonschema>=4.26; extra == 'test'
|
|
30
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'test'
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'test'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# tiergraph
|
|
35
|
+
|
|
36
|
+
*Ordered tiers, declared relations, and an algebra over them*
|
|
37
|
+
|
|
38
|
+
tiergraph holds parallel ordered sequences and the declared links between them
|
|
39
|
+
as one immutable graph, checked when it is built. Every view — selection,
|
|
40
|
+
traversal, containment, timing, folds — is computed from that one graph, so no
|
|
41
|
+
view can disagree with the store.
|
|
42
|
+
|
|
43
|
+
The shape is the track view of an audio or video editor: rows of items, ordered
|
|
44
|
+
within a row, aligned across rows, with links between rows. Aligned annotations
|
|
45
|
+
over a signal have it; so do layered timelines and structured documents whose
|
|
46
|
+
parts reference each other.
|
|
47
|
+
|
|
48
|
+
You have this problem already if:
|
|
49
|
+
|
|
50
|
+
- you can construct a state your own code treats as invalid;
|
|
51
|
+
- you keep a derived index beside the store and must remember to update both; or
|
|
52
|
+
- your serialized format breaks when you add a field.
|
|
53
|
+
|
|
54
|
+
The package requires Python 3.12 or later. A PyPI release is not yet available;
|
|
55
|
+
install it from a source checkout:
|
|
56
|
+
|
|
57
|
+
```console
|
|
58
|
+
git clone https://github.com/lenzo-ka/tiergraph.git
|
|
59
|
+
cd tiergraph
|
|
60
|
+
python -m pip install .
|
|
61
|
+
tiergraph --version
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## See an alignment
|
|
65
|
+
|
|
66
|
+
This caption graph links each word to its phones. Select `cat`, walk the declared
|
|
67
|
+
alignment, and the answer is visible in the input:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from tiergraph import ItemSelector, Walk, WalkDirection, select
|
|
71
|
+
from tiergraph.build import document
|
|
72
|
+
|
|
73
|
+
builder = document("https://example.com/captions", prefix="caption")
|
|
74
|
+
words = builder.tier(
|
|
75
|
+
"words",
|
|
76
|
+
("a", "cat", "sat"),
|
|
77
|
+
item_type="word",
|
|
78
|
+
membership="word-membership",
|
|
79
|
+
)
|
|
80
|
+
phones = builder.tier(
|
|
81
|
+
"phones",
|
|
82
|
+
("AH", "K", "AE", "T", "S", "AE-2", "T-2"),
|
|
83
|
+
item_type="phone",
|
|
84
|
+
membership="phone-membership",
|
|
85
|
+
)
|
|
86
|
+
aligns = builder.link(
|
|
87
|
+
"aligns",
|
|
88
|
+
words,
|
|
89
|
+
phones,
|
|
90
|
+
((0, 0), (1, 1), (1, 2), (1, 3), (2, 4), (2, 5), (2, 6)),
|
|
91
|
+
acyclic=True,
|
|
92
|
+
)
|
|
93
|
+
graph = builder.build()
|
|
94
|
+
|
|
95
|
+
cat = select(graph, (ItemSelector(graph, words.ref(1)),))
|
|
96
|
+
reached = Walk(cat, aligns.name, WalkDirection.FORWARD).evaluate().nodes
|
|
97
|
+
assert [node.reference for node in reached.nodes] == [
|
|
98
|
+
phones.ref(1),
|
|
99
|
+
phones.ref(2),
|
|
100
|
+
phones.ref(3),
|
|
101
|
+
]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The complete runnable example keeps the displayed phone labels separate from
|
|
105
|
+
their durable ids and prints `['K', 'AE', 'T']`; see
|
|
106
|
+
[`examples/caption_alignment.py`](examples/caption_alignment.py).
|
|
107
|
+
|
|
108
|
+
The model learned from Paul Hertz's Delta representation and the heterogeneous
|
|
109
|
+
relation graphs (HRGs) of the Festival Speech Synthesis System. tiergraph keeps
|
|
110
|
+
their emphasis on explicit tiered structure while defining a typed, immutable
|
|
111
|
+
model and a versioned interchange format.
|
|
112
|
+
|
|
113
|
+
Downstream migration (ipakit). ipakit is migrating onto tiergraph: Form's timed representation — units, intervals, positional lookup, and DOT rendering — is authoritative on the tiergraph library via a containment projection, with graph-independent identity hashing. The remaining backend subsystem graphs (such as pronunciation/CMU, mora, pinyin, gesture, and rewrite) and their JSON wire are still on ipakit's embedded graph engine and are being migrated to the library; when that completes the embedded engine is removed.
|
|
114
|
+
|
|
115
|
+
## What you can do with it
|
|
116
|
+
|
|
117
|
+
- Build a graph directly, or record an ordered edit stream as a `Program` and run
|
|
118
|
+
it — see [construction](docs/guide/construction.md).
|
|
119
|
+
- Select and traverse the structure, including ordered containment — see
|
|
120
|
+
[selection and traversal](docs/guide/selection-and-traversal.md).
|
|
121
|
+
- Fold a dependency graph with a semiring to measure or recognize it — see
|
|
122
|
+
[folding](docs/guide/folding.md) and [recognize and act](docs/guide/recognize-and-act.md).
|
|
123
|
+
- Attach a clock profile and resolve physical timing — see [timing](docs/guide/timing.md).
|
|
124
|
+
- Serialize to canonical JSON or render Graphviz DOT — see
|
|
125
|
+
[serialization](docs/guide/serialization.md).
|
|
126
|
+
- Project segmentation graphs into deterministic span views for JSON, JSON Lines,
|
|
127
|
+
text, HTML, or DOT — see [span views](docs/guide/span-views.md).
|
|
128
|
+
|
|
129
|
+
## Documentation
|
|
130
|
+
|
|
131
|
+
Start with the [documentation map](docs/README.md), then
|
|
132
|
+
[concepts](docs/concepts.md) for the data model and [getting
|
|
133
|
+
started](docs/getting-started.md) for a worked walkthrough. The [API
|
|
134
|
+
reference](docs/reference/api.md) covers every top-level export; the [CLI
|
|
135
|
+
reference](docs/reference/cli.md) is generated from the parser.
|
|
136
|
+
|
|
137
|
+
The companion `tiergraph_dot` package renders a graph as deterministic Graphviz
|
|
138
|
+
DOT and ships in the same distribution:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
import tiergraph_dot
|
|
142
|
+
|
|
143
|
+
dot = tiergraph_dot.dumps(graph)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Stability
|
|
147
|
+
|
|
148
|
+
tiergraph 0.1.x is alpha software. The public Python API may change before 1.0;
|
|
149
|
+
where possible, changes will be additive, but compatibility is not yet promised.
|
|
150
|
+
The JSON wire format, construction machine format, and span-view JSON format
|
|
151
|
+
carry explicit version stamps so a reader can identify the format it receives.
|
|
152
|
+
A format stamp identifies a contract; it does not imply that every version can
|
|
153
|
+
read or migrate every older format.
|
|
154
|
+
|
|
155
|
+
After 1.0, the intended policy is to announce a deprecated public Python API in
|
|
156
|
+
a minor release, retain it with a warning for at least one subsequent minor
|
|
157
|
+
release, and remove it only in a later release. Security, correctness, or
|
|
158
|
+
otherwise impractical compatibility constraints may require a faster change,
|
|
159
|
+
which will be documented in the release. This is an intended post-1.0 policy,
|
|
160
|
+
not a compatibility promise for the current alpha series.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# tiergraph
|
|
2
|
+
|
|
3
|
+
*Ordered tiers, declared relations, and an algebra over them*
|
|
4
|
+
|
|
5
|
+
tiergraph holds parallel ordered sequences and the declared links between them
|
|
6
|
+
as one immutable graph, checked when it is built. Every view — selection,
|
|
7
|
+
traversal, containment, timing, folds — is computed from that one graph, so no
|
|
8
|
+
view can disagree with the store.
|
|
9
|
+
|
|
10
|
+
The shape is the track view of an audio or video editor: rows of items, ordered
|
|
11
|
+
within a row, aligned across rows, with links between rows. Aligned annotations
|
|
12
|
+
over a signal have it; so do layered timelines and structured documents whose
|
|
13
|
+
parts reference each other.
|
|
14
|
+
|
|
15
|
+
You have this problem already if:
|
|
16
|
+
|
|
17
|
+
- you can construct a state your own code treats as invalid;
|
|
18
|
+
- you keep a derived index beside the store and must remember to update both; or
|
|
19
|
+
- your serialized format breaks when you add a field.
|
|
20
|
+
|
|
21
|
+
The package requires Python 3.12 or later. A PyPI release is not yet available;
|
|
22
|
+
install it from a source checkout:
|
|
23
|
+
|
|
24
|
+
```console
|
|
25
|
+
git clone https://github.com/lenzo-ka/tiergraph.git
|
|
26
|
+
cd tiergraph
|
|
27
|
+
python -m pip install .
|
|
28
|
+
tiergraph --version
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## See an alignment
|
|
32
|
+
|
|
33
|
+
This caption graph links each word to its phones. Select `cat`, walk the declared
|
|
34
|
+
alignment, and the answer is visible in the input:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from tiergraph import ItemSelector, Walk, WalkDirection, select
|
|
38
|
+
from tiergraph.build import document
|
|
39
|
+
|
|
40
|
+
builder = document("https://example.com/captions", prefix="caption")
|
|
41
|
+
words = builder.tier(
|
|
42
|
+
"words",
|
|
43
|
+
("a", "cat", "sat"),
|
|
44
|
+
item_type="word",
|
|
45
|
+
membership="word-membership",
|
|
46
|
+
)
|
|
47
|
+
phones = builder.tier(
|
|
48
|
+
"phones",
|
|
49
|
+
("AH", "K", "AE", "T", "S", "AE-2", "T-2"),
|
|
50
|
+
item_type="phone",
|
|
51
|
+
membership="phone-membership",
|
|
52
|
+
)
|
|
53
|
+
aligns = builder.link(
|
|
54
|
+
"aligns",
|
|
55
|
+
words,
|
|
56
|
+
phones,
|
|
57
|
+
((0, 0), (1, 1), (1, 2), (1, 3), (2, 4), (2, 5), (2, 6)),
|
|
58
|
+
acyclic=True,
|
|
59
|
+
)
|
|
60
|
+
graph = builder.build()
|
|
61
|
+
|
|
62
|
+
cat = select(graph, (ItemSelector(graph, words.ref(1)),))
|
|
63
|
+
reached = Walk(cat, aligns.name, WalkDirection.FORWARD).evaluate().nodes
|
|
64
|
+
assert [node.reference for node in reached.nodes] == [
|
|
65
|
+
phones.ref(1),
|
|
66
|
+
phones.ref(2),
|
|
67
|
+
phones.ref(3),
|
|
68
|
+
]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The complete runnable example keeps the displayed phone labels separate from
|
|
72
|
+
their durable ids and prints `['K', 'AE', 'T']`; see
|
|
73
|
+
[`examples/caption_alignment.py`](examples/caption_alignment.py).
|
|
74
|
+
|
|
75
|
+
The model learned from Paul Hertz's Delta representation and the heterogeneous
|
|
76
|
+
relation graphs (HRGs) of the Festival Speech Synthesis System. tiergraph keeps
|
|
77
|
+
their emphasis on explicit tiered structure while defining a typed, immutable
|
|
78
|
+
model and a versioned interchange format.
|
|
79
|
+
|
|
80
|
+
Downstream migration (ipakit). ipakit is migrating onto tiergraph: Form's timed representation — units, intervals, positional lookup, and DOT rendering — is authoritative on the tiergraph library via a containment projection, with graph-independent identity hashing. The remaining backend subsystem graphs (such as pronunciation/CMU, mora, pinyin, gesture, and rewrite) and their JSON wire are still on ipakit's embedded graph engine and are being migrated to the library; when that completes the embedded engine is removed.
|
|
81
|
+
|
|
82
|
+
## What you can do with it
|
|
83
|
+
|
|
84
|
+
- Build a graph directly, or record an ordered edit stream as a `Program` and run
|
|
85
|
+
it — see [construction](docs/guide/construction.md).
|
|
86
|
+
- Select and traverse the structure, including ordered containment — see
|
|
87
|
+
[selection and traversal](docs/guide/selection-and-traversal.md).
|
|
88
|
+
- Fold a dependency graph with a semiring to measure or recognize it — see
|
|
89
|
+
[folding](docs/guide/folding.md) and [recognize and act](docs/guide/recognize-and-act.md).
|
|
90
|
+
- Attach a clock profile and resolve physical timing — see [timing](docs/guide/timing.md).
|
|
91
|
+
- Serialize to canonical JSON or render Graphviz DOT — see
|
|
92
|
+
[serialization](docs/guide/serialization.md).
|
|
93
|
+
- Project segmentation graphs into deterministic span views for JSON, JSON Lines,
|
|
94
|
+
text, HTML, or DOT — see [span views](docs/guide/span-views.md).
|
|
95
|
+
|
|
96
|
+
## Documentation
|
|
97
|
+
|
|
98
|
+
Start with the [documentation map](docs/README.md), then
|
|
99
|
+
[concepts](docs/concepts.md) for the data model and [getting
|
|
100
|
+
started](docs/getting-started.md) for a worked walkthrough. The [API
|
|
101
|
+
reference](docs/reference/api.md) covers every top-level export; the [CLI
|
|
102
|
+
reference](docs/reference/cli.md) is generated from the parser.
|
|
103
|
+
|
|
104
|
+
The companion `tiergraph_dot` package renders a graph as deterministic Graphviz
|
|
105
|
+
DOT and ships in the same distribution:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
import tiergraph_dot
|
|
109
|
+
|
|
110
|
+
dot = tiergraph_dot.dumps(graph)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Stability
|
|
114
|
+
|
|
115
|
+
tiergraph 0.1.x is alpha software. The public Python API may change before 1.0;
|
|
116
|
+
where possible, changes will be additive, but compatibility is not yet promised.
|
|
117
|
+
The JSON wire format, construction machine format, and span-view JSON format
|
|
118
|
+
carry explicit version stamps so a reader can identify the format it receives.
|
|
119
|
+
A format stamp identifies a contract; it does not imply that every version can
|
|
120
|
+
read or migrate every older format.
|
|
121
|
+
|
|
122
|
+
After 1.0, the intended policy is to announce a deprecated public Python API in
|
|
123
|
+
a minor release, retain it with a warning for at least one subsequent minor
|
|
124
|
+
release, and remove it only in a later release. Security, correctness, or
|
|
125
|
+
otherwise impractical compatibility constraints may require a faster change,
|
|
126
|
+
which will be documented in the release. This is an intended post-1.0 policy,
|
|
127
|
+
not a compatibility promise for the current alpha series.
|