scriptoria 0.6.3__tar.gz → 0.6.4__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.
- {scriptoria-0.6.3 → scriptoria-0.6.4}/PKG-INFO +1 -1
- {scriptoria-0.6.3 → scriptoria-0.6.4}/pyproject.toml +1 -1
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/__init__.py +1 -1
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/blocks.py +3 -1
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/facts.py +5 -1
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_blocks.py +11 -0
- scriptoria-0.6.4/tests/test_facts.py +34 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/uv.lock +1 -1
- {scriptoria-0.6.3 → scriptoria-0.6.4}/.gitignore +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/README.md +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/pyrightconfig.json +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/anchors.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/cli.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/embeddings.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/errors.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/frontmatter.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/graph.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/hashing.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/ingest.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/lock.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/manifest.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/pageindex_adapter.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/query.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/retrieval.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/src/scrip/similar.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/conftest.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_anchor_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_anchors.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_embeddings.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_fact_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_frontmatter.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_graph_status.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_hashing.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_index_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_ingest.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_json_shapes.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_lock.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_manifest.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_new_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_pageindex_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_query.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_retrieval.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_similar_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_span_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_stamp.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_status_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_unlock_cmd.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_verify.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_version.py +0 -0
- {scriptoria-0.6.3 → scriptoria-0.6.4}/tests/test_watch.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scriptoria
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.4
|
|
4
4
|
Summary: Deterministic scriptorium-keeper (the `scrip` CLI): staleness, provenance integrity, and fact queries for an agent-compiled knowledge base
|
|
5
5
|
Project-URL: Homepage, https://github.com/coredipper/scriptorium
|
|
6
6
|
Project-URL: Changelog, https://github.com/coredipper/scriptorium/blob/main/CHANGELOG.md
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Distribution name on PyPI is `scriptoria` (scrip/scriptorium were taken); the
|
|
3
3
|
# CLI command and the import package both remain `scrip`.
|
|
4
4
|
name = "scriptoria"
|
|
5
|
-
version = "0.6.
|
|
5
|
+
version = "0.6.4"
|
|
6
6
|
description = "Deterministic scriptorium-keeper (the `scrip` CLI): staleness, provenance integrity, and fact queries for an agent-compiled knowledge base"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
requires-python = ">=3.10"
|
|
@@ -13,7 +13,7 @@ from __future__ import annotations
|
|
|
13
13
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
|
-
__version__ = "0.6.
|
|
16
|
+
__version__ = "0.6.4"
|
|
17
17
|
|
|
18
18
|
# --- canonical vault layout ------------------------------------------------
|
|
19
19
|
# ``root`` is the repo/instance root: the directory containing ``vault/``.
|
|
@@ -35,7 +35,9 @@ def _is_blank(line: str) -> bool:
|
|
|
35
35
|
|
|
36
36
|
def split_blocks(text: str) -> list[dict]:
|
|
37
37
|
"""Return a list of ``{"block_id", "span": [start, end], "hash"}``."""
|
|
38
|
-
#
|
|
38
|
+
# Use splitlines(keepends=True): its boundary set (form feed, NEL, U+2028/9,
|
|
39
|
+
# …) is part of the deterministic segmentation contract — io.StringIO only
|
|
40
|
+
# splits on \r/\n and would re-hash existing blocks that contain those chars.
|
|
39
41
|
ranges: list[list[int]] = [] # [start, end] per block
|
|
40
42
|
cur: list[int] | None = None
|
|
41
43
|
start = 0
|
|
@@ -77,7 +77,11 @@ def parse_ndjson(text: str) -> list[dict]:
|
|
|
77
77
|
"""Parse proposed records (one JSON object per line). Malformed input is a
|
|
78
78
|
:class:`DataError` with its line number; an empty input is a usage error."""
|
|
79
79
|
records: list[dict] = []
|
|
80
|
-
|
|
80
|
+
# Split on "\n" only, not str.splitlines(): NDJSON records are newline-
|
|
81
|
+
# delimited and may legally contain U+2028/U+2029/NEL inside a JSON string,
|
|
82
|
+
# which splitlines() would wrongly treat as record breaks. trailing \r (from
|
|
83
|
+
# \r\n) and the trailing empty element from a final newline are dropped below.
|
|
84
|
+
for lineno, raw_line in enumerate(text.split("\n"), start=1):
|
|
81
85
|
line = raw_line.strip()
|
|
82
86
|
if not line:
|
|
83
87
|
continue
|
|
@@ -151,3 +151,14 @@ def test_blank_runs_are_boundaries_not_blocks():
|
|
|
151
151
|
assert len(bs) == 1
|
|
152
152
|
s, e = bs[0]["span"]
|
|
153
153
|
assert "only paragraph" in "\n\nonly paragraph\n\n"[s:e]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_form_feed_is_a_line_boundary():
|
|
157
|
+
"""Segmentation uses str.splitlines()'s full boundary set (form feed here,
|
|
158
|
+
also NEL/U+2028/U+2029). Splitting only on \\r/\\n — e.g. via io.StringIO —
|
|
159
|
+
would merge these into one block and change every affected block's id/hash,
|
|
160
|
+
breaking the deterministic-segmentation contract (SPEC §7.2)."""
|
|
161
|
+
text = "# Heading\x0c## Sub\n"
|
|
162
|
+
spans = [tuple(b["span"]) for b in blocks.split_blocks(text)]
|
|
163
|
+
# two separate heading blocks, split at the form feed
|
|
164
|
+
assert spans == [(0, 10), (10, 17)]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from scrip.errors import DataError, UsageError
|
|
3
|
+
|
|
4
|
+
from scrip import facts
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_parse_ndjson_basic():
|
|
8
|
+
text = '{"a": 1}\n{"b": 2}\n'
|
|
9
|
+
assert facts.parse_ndjson(text) == [{"a": 1}, {"b": 2}]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_parse_ndjson_skips_blank_lines_and_strips_crlf():
|
|
13
|
+
text = '{"a": 1}\r\n\r\n{"b": 2}\r\n'
|
|
14
|
+
assert facts.parse_ndjson(text) == [{"a": 1}, {"b": 2}]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_parse_ndjson_keeps_u2028_inside_json_string():
|
|
18
|
+
# U+2028 / U+2029 are legal *inside* a JSON string value. str.splitlines()
|
|
19
|
+
# treats them as line breaks and would split this record into invalid
|
|
20
|
+
# fragments; splitting on "\n" only keeps the record intact.
|
|
21
|
+
text = '{"a": "x
y
z"}\n{"b": 2}\n'
|
|
22
|
+
assert facts.parse_ndjson(text) == [{"a": "x
y
z"}, {"b": 2}]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_parse_ndjson_reports_line_number_on_bad_json():
|
|
26
|
+
text = '{"a": 1}\nnot json\n'
|
|
27
|
+
with pytest.raises(DataError) as exc:
|
|
28
|
+
facts.parse_ndjson(text)
|
|
29
|
+
assert "line 2" in str(exc.value)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_parse_ndjson_empty_is_usage_error():
|
|
33
|
+
with pytest.raises(UsageError):
|
|
34
|
+
facts.parse_ndjson(" \n \n")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|