okf-parser 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.
- okf_parser-0.1.0/.github/workflows/ci.yml +111 -0
- okf_parser-0.1.0/.github/workflows/publish.yml +53 -0
- okf_parser-0.1.0/.gitignore +7 -0
- okf_parser-0.1.0/PKG-INFO +165 -0
- okf_parser-0.1.0/README.md +148 -0
- okf_parser-0.1.0/action.yml +20 -0
- okf_parser-0.1.0/changelog/0.1.0.md +20 -0
- okf_parser-0.1.0/fastmcp.json +17 -0
- okf_parser-0.1.0/pyproject.toml +55 -0
- okf_parser-0.1.0/rfcs/0001-python-model-codegen.md +325 -0
- okf_parser-0.1.0/src/okf_parser/__init__.py +13 -0
- okf_parser-0.1.0/src/okf_parser/bundle.py +368 -0
- okf_parser-0.1.0/src/okf_parser/cli.py +142 -0
- okf_parser-0.1.0/src/okf_parser/discovery.py +34 -0
- okf_parser-0.1.0/src/okf_parser/duckdb.py +87 -0
- okf_parser-0.1.0/src/okf_parser/formatting.py +46 -0
- okf_parser-0.1.0/src/okf_parser/models.py +86 -0
- okf_parser-0.1.0/src/okf_parser/parser.py +123 -0
- okf_parser-0.1.0/src/okf_parser/service.py +92 -0
- okf_parser-0.1.0/tests/__init__.py +1 -0
- okf_parser-0.1.0/tests/test_bundle.py +168 -0
- okf_parser-0.1.0/tests/test_duckdb.py +36 -0
- okf_parser-0.1.0/tests/test_formatting.py +57 -0
- okf_parser-0.1.0/tests/test_parser.py +63 -0
- okf_parser-0.1.0/uv.lock +1818 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
version-bump:
|
|
17
|
+
name: Version bump and changelog
|
|
18
|
+
if: github.event_name == 'pull_request'
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- name: Check out repository history
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0
|
|
25
|
+
|
|
26
|
+
- name: Require a version bump and matching changelog
|
|
27
|
+
shell: bash
|
|
28
|
+
env:
|
|
29
|
+
BASE: ${{ github.base_ref }}
|
|
30
|
+
run: |
|
|
31
|
+
set -euo pipefail
|
|
32
|
+
read_version() {
|
|
33
|
+
sed -n 's/^version = "\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)"$/\1/p'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
git fetch --quiet origin "$BASE"
|
|
37
|
+
head_version=$(read_version < pyproject.toml)
|
|
38
|
+
if git cat-file -e "origin/$BASE:pyproject.toml" 2>/dev/null; then
|
|
39
|
+
base_version=$(git show "origin/$BASE:pyproject.toml" | read_version)
|
|
40
|
+
else
|
|
41
|
+
base_version="0.0.0"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if [[ -z "$head_version" ]]; then
|
|
45
|
+
echo "::error file=pyproject.toml::A versão SemVer não foi encontrada."
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
if [[ "$head_version" == "$base_version" ]]; then
|
|
49
|
+
echo "::error file=pyproject.toml::A versão continua $head_version; faça o bump."
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
highest=$(printf '%s\n%s\n' "$base_version" "$head_version" | sort -V | tail -1)
|
|
53
|
+
if [[ "$highest" != "$head_version" ]]; then
|
|
54
|
+
echo "::error file=pyproject.toml::A versão $head_version não supera $base_version."
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
expected_changelog="changelog/$head_version.md"
|
|
59
|
+
mapfile -t added_changelogs < <(
|
|
60
|
+
git diff --diff-filter=A --name-only "origin/$BASE...HEAD" -- "changelog/*.md"
|
|
61
|
+
)
|
|
62
|
+
if [[ "${#added_changelogs[@]}" -ne 1 ]]; then
|
|
63
|
+
echo "::error file=changelog::Cada PR deve adicionar exatamente um changelog."
|
|
64
|
+
printf 'Encontrado: %s\n' "${added_changelogs[@]}"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
if [[ "${added_changelogs[0]}" != "$expected_changelog" ]]; then
|
|
68
|
+
echo "::error file=${added_changelogs[0]}::Esperado $expected_changelog."
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
echo "OK: $base_version -> $head_version; $expected_changelog presente."
|
|
73
|
+
|
|
74
|
+
quality:
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
steps:
|
|
77
|
+
- name: Check out repository
|
|
78
|
+
uses: actions/checkout@v4
|
|
79
|
+
|
|
80
|
+
- name: Install uv
|
|
81
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
82
|
+
with:
|
|
83
|
+
version: "0.11.21"
|
|
84
|
+
python-version: "3.12"
|
|
85
|
+
|
|
86
|
+
- name: Install locked dependencies
|
|
87
|
+
run: uv sync --frozen --all-groups
|
|
88
|
+
|
|
89
|
+
- name: Check lockfile
|
|
90
|
+
run: uv lock --check
|
|
91
|
+
|
|
92
|
+
- name: Check Python formatting
|
|
93
|
+
run: uv run ruff format --check .
|
|
94
|
+
|
|
95
|
+
- name: Lint Python
|
|
96
|
+
run: uv run ruff check .
|
|
97
|
+
|
|
98
|
+
- name: Check types
|
|
99
|
+
run: uv run ty check src tests
|
|
100
|
+
|
|
101
|
+
- name: Find dead code
|
|
102
|
+
run: uv run vulture src --min-confidence 90
|
|
103
|
+
|
|
104
|
+
- name: Run tests
|
|
105
|
+
run: uv run pytest
|
|
106
|
+
|
|
107
|
+
- name: Validate this repository with okf-parser
|
|
108
|
+
run: uv run okf-parser check .
|
|
109
|
+
|
|
110
|
+
- name: Build distributions
|
|
111
|
+
run: uv build
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Check out release
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
19
|
+
with:
|
|
20
|
+
version: "0.11.21"
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Verify release version
|
|
24
|
+
shell: bash
|
|
25
|
+
run: test "v$(uv version --short)" = "$GITHUB_REF_NAME"
|
|
26
|
+
|
|
27
|
+
- name: Build distributions
|
|
28
|
+
run: uv build
|
|
29
|
+
|
|
30
|
+
- name: Upload distributions
|
|
31
|
+
uses: actions/upload-artifact@v4
|
|
32
|
+
with:
|
|
33
|
+
name: python-package-distributions
|
|
34
|
+
path: dist/
|
|
35
|
+
if-no-files-found: error
|
|
36
|
+
|
|
37
|
+
publish:
|
|
38
|
+
needs: build
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
environment:
|
|
41
|
+
name: pypi
|
|
42
|
+
url: https://pypi.org/project/okf-parser/
|
|
43
|
+
permissions:
|
|
44
|
+
id-token: write
|
|
45
|
+
steps:
|
|
46
|
+
- name: Download distributions
|
|
47
|
+
uses: actions/download-artifact@v4
|
|
48
|
+
with:
|
|
49
|
+
name: python-package-distributions
|
|
50
|
+
path: dist/
|
|
51
|
+
|
|
52
|
+
- name: Publish distributions with attestations
|
|
53
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: okf-parser
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Relational inspection and validation for Open Knowledge Format bundles
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: cyclopts<5,>=4.22
|
|
7
|
+
Requires-Dist: duckdb<2,>=1.4
|
|
8
|
+
Requires-Dist: fastmcp<4,>=3.4
|
|
9
|
+
Requires-Dist: ibis-framework[duckdb]<13,>=12
|
|
10
|
+
Requires-Dist: markdown-it-py<5,>=4
|
|
11
|
+
Requires-Dist: mdformat-frontmatter<3,>=2
|
|
12
|
+
Requires-Dist: mdformat-gfm<2,>=1
|
|
13
|
+
Requires-Dist: mdformat<2,>=1
|
|
14
|
+
Requires-Dist: networkx<4,>=3.4
|
|
15
|
+
Requires-Dist: pyyaml<7,>=6
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
type: Project
|
|
20
|
+
title: okf-parser
|
|
21
|
+
description: Relational inspection and validation for Open Knowledge Format bundles
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# okf-parser
|
|
25
|
+
|
|
26
|
+
Relational inspection and validation for
|
|
27
|
+
[Open Knowledge Format (OKF) v0.2](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
|
|
28
|
+
bundles.
|
|
29
|
+
|
|
30
|
+
`okf-parser` reads an OKF bundle without imposing a domain taxonomy, preserves
|
|
31
|
+
unknown frontmatter fields, and exposes concepts and links as
|
|
32
|
+
[Ibis](https://ibis-project.org/) tables. This makes bundle-wide rules—identity,
|
|
33
|
+
lineage, cardinality, provenance, and profile-specific constraints—expressible
|
|
34
|
+
as deterministic relational checks.
|
|
35
|
+
|
|
36
|
+
## Why another OKF tool?
|
|
37
|
+
|
|
38
|
+
The ecosystem already has good static linters and generators, including
|
|
39
|
+
`okflint`, `okf-cli`, and `google-okf`. This project focuses on a different
|
|
40
|
+
layer:
|
|
41
|
+
|
|
42
|
+
- compile a bundle into queryable relational tables;
|
|
43
|
+
- project those same relations into a NetworkX graph;
|
|
44
|
+
- validate OKF v0.2 conformance without rejecting extensions;
|
|
45
|
+
- distinguish normative errors from advisory diagnostics;
|
|
46
|
+
- let projects add cross-concept rules as Ibis expressions;
|
|
47
|
+
- produce stable human-readable and JSON reports for CI and agents.
|
|
48
|
+
|
|
49
|
+
The parser and validation model are inspired by
|
|
50
|
+
[`franklinbaldo/sisprev`](https://github.com/franklinbaldo/sisprev): parse
|
|
51
|
+
documents independently from semantic validation, aggregate violations instead
|
|
52
|
+
of failing at the first bad concept, preserve authored bodies, and test
|
|
53
|
+
filesystem identity explicitly. No Sisprev-specific legal types are copied into
|
|
54
|
+
the core.
|
|
55
|
+
|
|
56
|
+
[`mrorigo/rust-okf`](https://github.com/mrorigo/rust-okf) inspired the stable
|
|
57
|
+
logical key, conservative metadata preservation, BOM/CRLF handling, and clean
|
|
58
|
+
separation between bundle parsing and downstream query surfaces. Its BM25,
|
|
59
|
+
vector index, storage format, and HTTP server are intentionally outside this
|
|
60
|
+
project's scope.
|
|
61
|
+
|
|
62
|
+
## Quick start
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv sync
|
|
66
|
+
uv run okf-parser check path/to/bundle
|
|
67
|
+
uv run okf-parser inventory path/to/bundle
|
|
68
|
+
uv run okf-parser graph path/to/bundle
|
|
69
|
+
uv run okf-parser format path/to/bundle
|
|
70
|
+
uv run okf-parser format path/to/bundle --write
|
|
71
|
+
uv run okf-parser duckdb path/to/bundle knowledge.duckdb
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The command exits with status `1` only when normative errors exist. Broken
|
|
75
|
+
cross-links are warnings because OKF v0.2 explicitly says they do not make a
|
|
76
|
+
bundle non-conformant.
|
|
77
|
+
|
|
78
|
+
## GitHub Actions
|
|
79
|
+
|
|
80
|
+
Add the repository as a CI check:
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@v4
|
|
85
|
+
- uses: franklinbaldo/okf-parser@v1
|
|
86
|
+
with:
|
|
87
|
+
path: knowledge
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The composite action installs a pinned uv version and executes the same
|
|
91
|
+
`validate_path()` function used by the Python API, CLI, and MCP server.
|
|
92
|
+
|
|
93
|
+
Releases are published to PyPI from GitHub Releases through OIDC Trusted
|
|
94
|
+
Publishing. No long-lived PyPI token is stored in the repository.
|
|
95
|
+
|
|
96
|
+
Every pull request must increase the SemVer version in `pyproject.toml` and add
|
|
97
|
+
exactly one matching `changelog/<version>.md` entry. CI compares both against
|
|
98
|
+
the target branch before allowing merge.
|
|
99
|
+
|
|
100
|
+
## MCP
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
uv run okf-parser serve
|
|
104
|
+
uv run okf-parser-mcp
|
|
105
|
+
uv run fastmcp run
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Read-only tools: `check`, `inventory`, `graph`, and `format_check`.
|
|
109
|
+
|
|
110
|
+
## DuckDB
|
|
111
|
+
|
|
112
|
+
`okf-parser` is a regular uv-managed Python app; the DuckDB integration is part
|
|
113
|
+
of the same package, not a native C++ subproject:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
import duckdb
|
|
117
|
+
|
|
118
|
+
from okf_parser.duckdb import attach_okf
|
|
119
|
+
|
|
120
|
+
connection = duckdb.connect("knowledge.duckdb")
|
|
121
|
+
attach_okf(connection, "knowledge/")
|
|
122
|
+
|
|
123
|
+
connection.sql("""
|
|
124
|
+
SELECT concept_type, count(*)
|
|
125
|
+
FROM okf.concepts
|
|
126
|
+
GROUP BY concept_type
|
|
127
|
+
""").show()
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The call creates `okf.concepts`, `okf.links`, `okf.reserved`, and
|
|
131
|
+
`okf.diagnostics` as ordinary DuckDB tables. Use a new database or schema for
|
|
132
|
+
each materialization.
|
|
133
|
+
|
|
134
|
+
## Python API
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from pathlib import Path
|
|
138
|
+
|
|
139
|
+
from okf_parser import load_bundle, validate_path
|
|
140
|
+
|
|
141
|
+
bundle = load_bundle(Path("knowledge"))
|
|
142
|
+
print(bundle.concepts.execute())
|
|
143
|
+
print(bundle.links.execute())
|
|
144
|
+
print(bundle.to_networkx())
|
|
145
|
+
print(bundle.validate())
|
|
146
|
+
|
|
147
|
+
report = validate_path(Path("knowledge"))
|
|
148
|
+
assert report.markdown_count == report.concept_count + report.reserved_count
|
|
149
|
+
assert report.is_conformant
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Current scope
|
|
153
|
+
|
|
154
|
+
- UTF-8 Markdown discovery;
|
|
155
|
+
- reserved `index.md` and `log.md` handling;
|
|
156
|
+
- strict YAML-frontmatter parsing for concept documents;
|
|
157
|
+
- required non-empty `type`;
|
|
158
|
+
- stable concept IDs derived from paths;
|
|
159
|
+
- Markdown-link extraction and resolution;
|
|
160
|
+
- Ibis tables for concepts, reserved documents, and links;
|
|
161
|
+
- NetworkX graph projection for traversal, cycles, components, and impact;
|
|
162
|
+
- aggregated validation reports.
|
|
163
|
+
|
|
164
|
+
Profiles, lifecycle/provenance family validation, external resources, and
|
|
165
|
+
pluggable Ibis rules are the next milestones.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Project
|
|
3
|
+
title: okf-parser
|
|
4
|
+
description: Relational inspection and validation for Open Knowledge Format bundles
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# okf-parser
|
|
8
|
+
|
|
9
|
+
Relational inspection and validation for
|
|
10
|
+
[Open Knowledge Format (OKF) v0.2](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
|
|
11
|
+
bundles.
|
|
12
|
+
|
|
13
|
+
`okf-parser` reads an OKF bundle without imposing a domain taxonomy, preserves
|
|
14
|
+
unknown frontmatter fields, and exposes concepts and links as
|
|
15
|
+
[Ibis](https://ibis-project.org/) tables. This makes bundle-wide rules—identity,
|
|
16
|
+
lineage, cardinality, provenance, and profile-specific constraints—expressible
|
|
17
|
+
as deterministic relational checks.
|
|
18
|
+
|
|
19
|
+
## Why another OKF tool?
|
|
20
|
+
|
|
21
|
+
The ecosystem already has good static linters and generators, including
|
|
22
|
+
`okflint`, `okf-cli`, and `google-okf`. This project focuses on a different
|
|
23
|
+
layer:
|
|
24
|
+
|
|
25
|
+
- compile a bundle into queryable relational tables;
|
|
26
|
+
- project those same relations into a NetworkX graph;
|
|
27
|
+
- validate OKF v0.2 conformance without rejecting extensions;
|
|
28
|
+
- distinguish normative errors from advisory diagnostics;
|
|
29
|
+
- let projects add cross-concept rules as Ibis expressions;
|
|
30
|
+
- produce stable human-readable and JSON reports for CI and agents.
|
|
31
|
+
|
|
32
|
+
The parser and validation model are inspired by
|
|
33
|
+
[`franklinbaldo/sisprev`](https://github.com/franklinbaldo/sisprev): parse
|
|
34
|
+
documents independently from semantic validation, aggregate violations instead
|
|
35
|
+
of failing at the first bad concept, preserve authored bodies, and test
|
|
36
|
+
filesystem identity explicitly. No Sisprev-specific legal types are copied into
|
|
37
|
+
the core.
|
|
38
|
+
|
|
39
|
+
[`mrorigo/rust-okf`](https://github.com/mrorigo/rust-okf) inspired the stable
|
|
40
|
+
logical key, conservative metadata preservation, BOM/CRLF handling, and clean
|
|
41
|
+
separation between bundle parsing and downstream query surfaces. Its BM25,
|
|
42
|
+
vector index, storage format, and HTTP server are intentionally outside this
|
|
43
|
+
project's scope.
|
|
44
|
+
|
|
45
|
+
## Quick start
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv sync
|
|
49
|
+
uv run okf-parser check path/to/bundle
|
|
50
|
+
uv run okf-parser inventory path/to/bundle
|
|
51
|
+
uv run okf-parser graph path/to/bundle
|
|
52
|
+
uv run okf-parser format path/to/bundle
|
|
53
|
+
uv run okf-parser format path/to/bundle --write
|
|
54
|
+
uv run okf-parser duckdb path/to/bundle knowledge.duckdb
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The command exits with status `1` only when normative errors exist. Broken
|
|
58
|
+
cross-links are warnings because OKF v0.2 explicitly says they do not make a
|
|
59
|
+
bundle non-conformant.
|
|
60
|
+
|
|
61
|
+
## GitHub Actions
|
|
62
|
+
|
|
63
|
+
Add the repository as a CI check:
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/checkout@v4
|
|
68
|
+
- uses: franklinbaldo/okf-parser@v1
|
|
69
|
+
with:
|
|
70
|
+
path: knowledge
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The composite action installs a pinned uv version and executes the same
|
|
74
|
+
`validate_path()` function used by the Python API, CLI, and MCP server.
|
|
75
|
+
|
|
76
|
+
Releases are published to PyPI from GitHub Releases through OIDC Trusted
|
|
77
|
+
Publishing. No long-lived PyPI token is stored in the repository.
|
|
78
|
+
|
|
79
|
+
Every pull request must increase the SemVer version in `pyproject.toml` and add
|
|
80
|
+
exactly one matching `changelog/<version>.md` entry. CI compares both against
|
|
81
|
+
the target branch before allowing merge.
|
|
82
|
+
|
|
83
|
+
## MCP
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
uv run okf-parser serve
|
|
87
|
+
uv run okf-parser-mcp
|
|
88
|
+
uv run fastmcp run
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Read-only tools: `check`, `inventory`, `graph`, and `format_check`.
|
|
92
|
+
|
|
93
|
+
## DuckDB
|
|
94
|
+
|
|
95
|
+
`okf-parser` is a regular uv-managed Python app; the DuckDB integration is part
|
|
96
|
+
of the same package, not a native C++ subproject:
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
import duckdb
|
|
100
|
+
|
|
101
|
+
from okf_parser.duckdb import attach_okf
|
|
102
|
+
|
|
103
|
+
connection = duckdb.connect("knowledge.duckdb")
|
|
104
|
+
attach_okf(connection, "knowledge/")
|
|
105
|
+
|
|
106
|
+
connection.sql("""
|
|
107
|
+
SELECT concept_type, count(*)
|
|
108
|
+
FROM okf.concepts
|
|
109
|
+
GROUP BY concept_type
|
|
110
|
+
""").show()
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The call creates `okf.concepts`, `okf.links`, `okf.reserved`, and
|
|
114
|
+
`okf.diagnostics` as ordinary DuckDB tables. Use a new database or schema for
|
|
115
|
+
each materialization.
|
|
116
|
+
|
|
117
|
+
## Python API
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from pathlib import Path
|
|
121
|
+
|
|
122
|
+
from okf_parser import load_bundle, validate_path
|
|
123
|
+
|
|
124
|
+
bundle = load_bundle(Path("knowledge"))
|
|
125
|
+
print(bundle.concepts.execute())
|
|
126
|
+
print(bundle.links.execute())
|
|
127
|
+
print(bundle.to_networkx())
|
|
128
|
+
print(bundle.validate())
|
|
129
|
+
|
|
130
|
+
report = validate_path(Path("knowledge"))
|
|
131
|
+
assert report.markdown_count == report.concept_count + report.reserved_count
|
|
132
|
+
assert report.is_conformant
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Current scope
|
|
136
|
+
|
|
137
|
+
- UTF-8 Markdown discovery;
|
|
138
|
+
- reserved `index.md` and `log.md` handling;
|
|
139
|
+
- strict YAML-frontmatter parsing for concept documents;
|
|
140
|
+
- required non-empty `type`;
|
|
141
|
+
- stable concept IDs derived from paths;
|
|
142
|
+
- Markdown-link extraction and resolution;
|
|
143
|
+
- Ibis tables for concepts, reserved documents, and links;
|
|
144
|
+
- NetworkX graph projection for traversal, cycles, components, and impact;
|
|
145
|
+
- aggregated validation reports.
|
|
146
|
+
|
|
147
|
+
Profiles, lifecycle/provenance family validation, external resources, and
|
|
148
|
+
pluggable Ibis rules are the next milestones.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Validate OKF bundle
|
|
2
|
+
description: Validate every Markdown file below a path as Open Knowledge Format v0.2
|
|
3
|
+
inputs:
|
|
4
|
+
path:
|
|
5
|
+
description: Bundle directory to validate
|
|
6
|
+
required: false
|
|
7
|
+
default: .
|
|
8
|
+
runs:
|
|
9
|
+
using: composite
|
|
10
|
+
steps:
|
|
11
|
+
- name: Install uv
|
|
12
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
13
|
+
with:
|
|
14
|
+
version: "0.11.21"
|
|
15
|
+
- name: Validate OKF
|
|
16
|
+
shell: bash
|
|
17
|
+
env:
|
|
18
|
+
OKF_PATH: ${{ inputs.path }}
|
|
19
|
+
run: |
|
|
20
|
+
uv run --project "$GITHUB_ACTION_PATH" --frozen okf-parser check "$OKF_PATH"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: ChangelogEntry
|
|
3
|
+
title: okf-parser 0.1.0
|
|
4
|
+
description: Initial release of the relational OKF validation toolkit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# okf-parser 0.1.0
|
|
8
|
+
|
|
9
|
+
- Validate complete OKF v0.2 bundles with aggregated diagnostics.
|
|
10
|
+
- Query concepts and links through Ibis and materialize them in DuckDB.
|
|
11
|
+
- Project bundle relationships into NetworkX graphs.
|
|
12
|
+
- Expose Cyclopts CLI commands and read-only FastMCP tools.
|
|
13
|
+
- Check or apply Markdown formatting with mdformat.
|
|
14
|
+
- Reuse validation through a composite GitHub Action.
|
|
15
|
+
- Publish signed PyPI releases through OIDC Trusted Publishing.
|
|
16
|
+
- Validate the repository with `okf-parser` itself in CI.
|
|
17
|
+
- Propose bidirectional code generation between OKF profiles and Python models.
|
|
18
|
+
- Reserve only normative `index.md` and `log.md` documents.
|
|
19
|
+
- Discover Markdown consistently without traversing environments or symlinks.
|
|
20
|
+
- Extract links through CommonMark tokens and use portable concept keys.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://gofastmcp.com/public/schemas/fastmcp.json/v1.json",
|
|
3
|
+
"source": {
|
|
4
|
+
"type": "filesystem",
|
|
5
|
+
"path": "src/okf_parser/cli.py",
|
|
6
|
+
"entrypoint": "mcp"
|
|
7
|
+
},
|
|
8
|
+
"environment": {
|
|
9
|
+
"type": "uv",
|
|
10
|
+
"python": "3.12",
|
|
11
|
+
"project": "."
|
|
12
|
+
},
|
|
13
|
+
"deployment": {
|
|
14
|
+
"transport": "stdio",
|
|
15
|
+
"log_level": "INFO"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "okf-parser"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Relational inspection and validation for Open Knowledge Format bundles"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"cyclopts>=4.22,<5",
|
|
9
|
+
"duckdb>=1.4,<2",
|
|
10
|
+
"fastmcp>=3.4,<4",
|
|
11
|
+
"ibis-framework[duckdb]>=12,<13",
|
|
12
|
+
"markdown-it-py>=4,<5",
|
|
13
|
+
"mdformat>=1,<2",
|
|
14
|
+
"mdformat-frontmatter>=2,<3",
|
|
15
|
+
"mdformat-gfm>=1,<2",
|
|
16
|
+
"networkx>=3.4,<4",
|
|
17
|
+
"pyyaml>=6,<7",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.scripts]
|
|
21
|
+
okf-parser = "okf_parser.cli:main"
|
|
22
|
+
okf-parser-mcp = "okf_parser.cli:run_mcp_stdio"
|
|
23
|
+
|
|
24
|
+
[dependency-groups]
|
|
25
|
+
dev = [
|
|
26
|
+
"pytest>=8,<10",
|
|
27
|
+
"ruff>=0.15,<0.16",
|
|
28
|
+
"ty>=0.0.1a20,<0.1",
|
|
29
|
+
"vulture>=2.14,<3",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[build-system]
|
|
33
|
+
requires = ["hatchling"]
|
|
34
|
+
build-backend = "hatchling.build"
|
|
35
|
+
|
|
36
|
+
[tool.pytest.ini_options]
|
|
37
|
+
testpaths = ["tests"]
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
line-length = 100
|
|
41
|
+
target-version = "py312"
|
|
42
|
+
|
|
43
|
+
[tool.ruff.lint]
|
|
44
|
+
select = ["ALL"]
|
|
45
|
+
ignore = [
|
|
46
|
+
"COM812",
|
|
47
|
+
"ISC001",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint.per-file-ignores]
|
|
51
|
+
"src/okf_parser/cli.py" = ["T201"]
|
|
52
|
+
"tests/*" = ["D103", "PLR2004", "S101"]
|
|
53
|
+
|
|
54
|
+
[tool.ruff.lint.pydocstyle]
|
|
55
|
+
convention = "google"
|