assurance-cli 0.2.2__tar.gz → 0.3.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.
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/PKG-INFO +16 -2
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/README.md +14 -0
- assurance_cli-0.3.0/assurance_cli/__init__.py +19 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli/baseline.py +22 -2
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli/cli.py +12 -2
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli/gather.py +18 -5
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli.egg-info/PKG-INFO +16 -2
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli.egg-info/SOURCES.txt +2 -1
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli.egg-info/requires.txt +1 -1
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/pyproject.toml +2 -2
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/tests/test_cli.py +23 -0
- assurance_cli-0.3.0/tests/test_version.py +33 -0
- assurance_cli-0.2.2/assurance_cli/__init__.py +0 -8
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/LICENSE +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli/__main__.py +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli/paths.py +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli/profile.py +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli/setdiff.py +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli.egg-info/dependency_links.txt +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli.egg-info/entry_points.txt +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/assurance_cli.egg-info/top_level.txt +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/setup.cfg +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/tests/test_read_only.py +0 -0
- {assurance_cli-0.2.2 → assurance_cli-0.3.0}/tests/test_setdiff.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: assurance-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: CLI for folder assurance checks — coverage, staleness, and baselines.
|
|
5
5
|
Author-email: "I-Ops Operations Intelligence, LLC" <hello@i-ops.dev>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
|
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: assurance-core>=0.
|
|
22
|
+
Requires-Dist: assurance-core>=0.4
|
|
23
23
|
Requires-Dist: openpyxl>=3.1
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
@@ -56,6 +56,10 @@ No account · no API key · no network call · **no model decides any of it**
|
|
|
56
56
|
|
|
57
57
|
## Three commands
|
|
58
58
|
|
|
59
|
+
**`diff` is the general one.** `check` is the special case for a folder of
|
|
60
|
+
dated or numbered *tabular* files — if your files are `.md`, or named in a format it can't read, use
|
|
61
|
+
`diff` and declare the set yourself.
|
|
62
|
+
|
|
59
63
|
### `assurance diff` — any two sets of keys
|
|
60
64
|
|
|
61
65
|
```bash
|
|
@@ -95,10 +99,20 @@ assurance check ~/invoices --expect numbered
|
|
|
95
99
|
Monthly, quarterly, weekly, daily, numbered. That last line is the **derivation**: it prints with
|
|
96
100
|
every ratio so you can disagree with the denominator, not just the result.
|
|
97
101
|
|
|
102
|
+
When a file is there under a name it can't read, it says so beside the gap, because that's the
|
|
103
|
+
difference between *never produced* and *produced and named differently*:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
11 of 12 months from 2025-01 to 2025-12 — not in this folder: March 2025
|
|
107
|
+
— 1 name here could not be read as any of them: March FINAL v2.csv
|
|
108
|
+
```
|
|
109
|
+
|
|
98
110
|
### `assurance init` — did anything change underneath?
|
|
99
111
|
|
|
100
112
|
```bash
|
|
101
113
|
assurance init ~/thesis-data
|
|
114
|
+
# Baseline written to ~/thesis-data/.assurance.json — 34 tabular files recorded.
|
|
115
|
+
|
|
102
116
|
# ... weeks pass, several people touch the folder ...
|
|
103
117
|
assurance check ~/thesis-data --against-baseline
|
|
104
118
|
```
|
|
@@ -29,6 +29,10 @@ No account · no API key · no network call · **no model decides any of it**
|
|
|
29
29
|
|
|
30
30
|
## Three commands
|
|
31
31
|
|
|
32
|
+
**`diff` is the general one.** `check` is the special case for a folder of
|
|
33
|
+
dated or numbered *tabular* files — if your files are `.md`, or named in a format it can't read, use
|
|
34
|
+
`diff` and declare the set yourself.
|
|
35
|
+
|
|
32
36
|
### `assurance diff` — any two sets of keys
|
|
33
37
|
|
|
34
38
|
```bash
|
|
@@ -68,10 +72,20 @@ assurance check ~/invoices --expect numbered
|
|
|
68
72
|
Monthly, quarterly, weekly, daily, numbered. That last line is the **derivation**: it prints with
|
|
69
73
|
every ratio so you can disagree with the denominator, not just the result.
|
|
70
74
|
|
|
75
|
+
When a file is there under a name it can't read, it says so beside the gap, because that's the
|
|
76
|
+
difference between *never produced* and *produced and named differently*:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
11 of 12 months from 2025-01 to 2025-12 — not in this folder: March 2025
|
|
80
|
+
— 1 name here could not be read as any of them: March FINAL v2.csv
|
|
81
|
+
```
|
|
82
|
+
|
|
71
83
|
### `assurance init` — did anything change underneath?
|
|
72
84
|
|
|
73
85
|
```bash
|
|
74
86
|
assurance init ~/thesis-data
|
|
87
|
+
# Baseline written to ~/thesis-data/.assurance.json — 34 tabular files recorded.
|
|
88
|
+
|
|
75
89
|
# ... weeks pass, several people touch the folder ...
|
|
76
90
|
assurance check ~/thesis-data --against-baseline
|
|
77
91
|
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""assurance-cli — folder checks anyone can run without I-Ops.
|
|
2
|
+
|
|
3
|
+
Shared filesystem I/O (`paths`, `profile`, `gather`) lives in this package so `assurance-mcp` can
|
|
4
|
+
import it instead of duplicating the profiler. MCP depends on this package for gathering only; the
|
|
5
|
+
CLI does not depend on MCP. Two copies of the profiler is how they disagree.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Read from the installed distribution rather than typed here. A hardcoded literal is a second place
|
|
9
|
+
# the version lives, and the second place is the one that goes stale: these sat at "0.1.0" through
|
|
10
|
+
# five releases and were reported by an outside reviewer on 2026-08-29. One source of truth is
|
|
11
|
+
# `pyproject.toml`, and this reads what was actually installed from it.
|
|
12
|
+
from importlib.metadata import PackageNotFoundError, version as _version
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
__version__ = _version("assurance-cli")
|
|
16
|
+
except PackageNotFoundError: # running from a source tree that was never installed
|
|
17
|
+
__version__ = "0.0.0+unknown"
|
|
18
|
+
|
|
19
|
+
__all__ = ["__version__"]
|
|
@@ -19,7 +19,12 @@ def init_baseline(folder: str, *, update: bool = False) -> dict[str, Any]:
|
|
|
19
19
|
root = resolve_folder(folder)
|
|
20
20
|
path = root / BASELINE_NAME
|
|
21
21
|
if path.exists() and not update:
|
|
22
|
-
return {
|
|
22
|
+
return {
|
|
23
|
+
"written": False,
|
|
24
|
+
"path": str(path),
|
|
25
|
+
"reason": "baseline already exists; use --update",
|
|
26
|
+
"summary": f"A baseline already exists at {path}. Pass --update to overwrite it.",
|
|
27
|
+
}
|
|
23
28
|
|
|
24
29
|
entries: dict[str, Any] = {}
|
|
25
30
|
for file_path in sorted(root.rglob("*")):
|
|
@@ -50,7 +55,22 @@ def init_baseline(folder: str, *, update: bool = False) -> dict[str, Any]:
|
|
|
50
55
|
"files": entries,
|
|
51
56
|
}
|
|
52
57
|
path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
53
|
-
|
|
58
|
+
# A summary, because text mode renders one and prints nothing without it. `assurance init`
|
|
59
|
+
# wrote the file and then said nothing at all, so success was indistinguishable from a hung
|
|
60
|
+
# command — reported by an outside reviewer 2026-08-29. The count is the useful half: a baseline
|
|
61
|
+
# over zero files is a baseline that will never notice anything.
|
|
62
|
+
noun = "file" if len(entries) == 1 else "files"
|
|
63
|
+
return {
|
|
64
|
+
"written": True,
|
|
65
|
+
"path": str(path),
|
|
66
|
+
"file_count": len(entries),
|
|
67
|
+
"summary": (
|
|
68
|
+
f"Baseline written to {path} — {len(entries)} tabular {noun} recorded. "
|
|
69
|
+
"Re-check with `assurance check <folder> --against-baseline`."
|
|
70
|
+
if entries
|
|
71
|
+
else f"Baseline written to {path} — no tabular files found, so it records nothing."
|
|
72
|
+
),
|
|
73
|
+
}
|
|
54
74
|
|
|
55
75
|
|
|
56
76
|
def check_against_baseline(folder: str) -> dict[str, Any]:
|
|
@@ -14,14 +14,24 @@ from assurance_cli.setdiff import KeySpecError, diff_sets, format_diff
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def main(argv: list[str] | None = None) -> int:
|
|
17
|
-
parser = argparse.ArgumentParser(
|
|
17
|
+
parser = argparse.ArgumentParser(
|
|
18
|
+
prog="assurance",
|
|
19
|
+
description=(
|
|
20
|
+
"Did the job cover everything it was supposed to cover? Arithmetic, not models. "
|
|
21
|
+
"`diff` is the general command — it compares any two sets of keys. `check` is the "
|
|
22
|
+
"special case for a folder of dated or numbered files."
|
|
23
|
+
),
|
|
24
|
+
)
|
|
18
25
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
19
26
|
|
|
20
27
|
init_parser = sub.add_parser("init", help="Write .assurance.json baseline")
|
|
21
28
|
init_parser.add_argument("folder", help="Folder to baseline")
|
|
22
29
|
init_parser.add_argument("--update", action="store_true", help="Overwrite an existing baseline")
|
|
23
30
|
|
|
24
|
-
check_parser = sub.add_parser(
|
|
31
|
+
check_parser = sub.add_parser(
|
|
32
|
+
"check",
|
|
33
|
+
help="Special case: a folder of DATED or NUMBERED files (tabular). For anything else use `diff`",
|
|
34
|
+
)
|
|
25
35
|
check_parser.add_argument("folder", help="Folder to check")
|
|
26
36
|
check_parser.add_argument("--expect", choices=["monthly", "quarterly", "weekly", "daily", "numbered"])
|
|
27
37
|
check_parser.add_argument("--from", dest="from_point", metavar="FROM")
|
|
@@ -25,6 +25,8 @@ from assurance_cli.profile import TABULAR_SUFFIXES, profile_file
|
|
|
25
25
|
|
|
26
26
|
MAX_PERIODS = 36
|
|
27
27
|
MAX_NUMBERED = 500
|
|
28
|
+
# Enough to say "it is probably right there" without pasting a whole directory into one sentence.
|
|
29
|
+
MAX_UNREAD = 20
|
|
28
30
|
MIN_FILES_TO_INFER = 3
|
|
29
31
|
|
|
30
32
|
_KIND_FROM_NAME = {
|
|
@@ -39,7 +41,7 @@ _KIND_FROM_NAME = {
|
|
|
39
41
|
def list_dated_files(folder: str) -> dict[str, Any]:
|
|
40
42
|
"""List sequence points present in a folder from dated tabular filenames."""
|
|
41
43
|
root = resolve_folder(folder)
|
|
42
|
-
by_key = _indexed_files(root)
|
|
44
|
+
by_key, unread = _indexed_files(root)
|
|
43
45
|
keys = sorted(by_key)
|
|
44
46
|
return {
|
|
45
47
|
"folder": str(root),
|
|
@@ -65,7 +67,7 @@ def check_coverage(
|
|
|
65
67
|
) -> dict[str, Any]:
|
|
66
68
|
"""Check whether every step in the span is present — cold start, no prior state."""
|
|
67
69
|
root = resolve_folder(folder)
|
|
68
|
-
by_key = _indexed_files(root)
|
|
70
|
+
by_key, unread = _indexed_files(root)
|
|
69
71
|
if not by_key:
|
|
70
72
|
return {
|
|
71
73
|
"folder": str(root),
|
|
@@ -132,7 +134,7 @@ def check_coverage(
|
|
|
132
134
|
truncated = f"stopped at {cap} {unit}"
|
|
133
135
|
expected_keys = expected_keys[-cap:]
|
|
134
136
|
|
|
135
|
-
cov = Coverage(scope_label=scope, truncated=truncated, derivation=derivation)
|
|
137
|
+
cov = Coverage(scope_label=scope, truncated=truncated, derivation=derivation, unmatched=unread)
|
|
136
138
|
for key, label in expected_keys:
|
|
137
139
|
expectation = Expectation(key=key, label=label, why=derivation or f"in {scope}")
|
|
138
140
|
cov.expected.append(expectation)
|
|
@@ -218,8 +220,17 @@ def check_staleness(
|
|
|
218
220
|
return _finding_to_dict(finding)
|
|
219
221
|
|
|
220
222
|
|
|
221
|
-
def _indexed_files(root: Path) -> dict[str, list[Path]]:
|
|
223
|
+
def _indexed_files(root: Path) -> tuple[dict[str, list[Path]], list[str]]:
|
|
224
|
+
"""The files that parse to a point, and the names of the tabular files that do not.
|
|
225
|
+
|
|
226
|
+
That second list used to be `continue` and nothing else. It is the difference between two causes
|
|
227
|
+
that produce an identical `missing` line — never produced, or produced under a name the
|
|
228
|
+
enumeration could not read — and it was being discarded at the one moment we had it. A folder of
|
|
229
|
+
twelve files, eleven parsing as months and one called "March FINAL v2.csv", reported March as
|
|
230
|
+
not in the folder and never mentioned the twelfth file anywhere.
|
|
231
|
+
"""
|
|
222
232
|
found: dict[str, list[Path]] = {}
|
|
233
|
+
unread: list[str] = []
|
|
223
234
|
for path in sorted(root.rglob("*")):
|
|
224
235
|
if not path.is_file() or path.suffix.lower() not in TABULAR_SUFFIXES:
|
|
225
236
|
continue
|
|
@@ -231,10 +242,11 @@ def _indexed_files(root: Path) -> dict[str, list[Path]]:
|
|
|
231
242
|
continue
|
|
232
243
|
point = point_from_filename(path.name)
|
|
233
244
|
if point is None:
|
|
245
|
+
unread.append(path.name)
|
|
234
246
|
continue
|
|
235
247
|
key = point_key(point) # type: ignore[arg-type]
|
|
236
248
|
found.setdefault(key, []).append(path)
|
|
237
|
-
return found
|
|
249
|
+
return found, unread[:MAX_UNREAD]
|
|
238
250
|
|
|
239
251
|
|
|
240
252
|
def _label_for_key(key: str, filename: str) -> str:
|
|
@@ -296,6 +308,7 @@ def _coverage_to_dict(cov: Coverage) -> dict[str, Any]:
|
|
|
296
308
|
"gone": dict(cov.gone),
|
|
297
309
|
"ambiguous": dict(cov.ambiguous),
|
|
298
310
|
"unreadable": dict(cov.unreadable),
|
|
311
|
+
"unmatched": list(cov.unmatched),
|
|
299
312
|
"unauthorized": dict(cov.unauthorized),
|
|
300
313
|
"truncated": cov.truncated,
|
|
301
314
|
"undetermined": cov.undetermined,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: assurance-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: CLI for folder assurance checks — coverage, staleness, and baselines.
|
|
5
5
|
Author-email: "I-Ops Operations Intelligence, LLC" <hello@i-ops.dev>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
|
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: assurance-core>=0.
|
|
22
|
+
Requires-Dist: assurance-core>=0.4
|
|
23
23
|
Requires-Dist: openpyxl>=3.1
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
@@ -56,6 +56,10 @@ No account · no API key · no network call · **no model decides any of it**
|
|
|
56
56
|
|
|
57
57
|
## Three commands
|
|
58
58
|
|
|
59
|
+
**`diff` is the general one.** `check` is the special case for a folder of
|
|
60
|
+
dated or numbered *tabular* files — if your files are `.md`, or named in a format it can't read, use
|
|
61
|
+
`diff` and declare the set yourself.
|
|
62
|
+
|
|
59
63
|
### `assurance diff` — any two sets of keys
|
|
60
64
|
|
|
61
65
|
```bash
|
|
@@ -95,10 +99,20 @@ assurance check ~/invoices --expect numbered
|
|
|
95
99
|
Monthly, quarterly, weekly, daily, numbered. That last line is the **derivation**: it prints with
|
|
96
100
|
every ratio so you can disagree with the denominator, not just the result.
|
|
97
101
|
|
|
102
|
+
When a file is there under a name it can't read, it says so beside the gap, because that's the
|
|
103
|
+
difference between *never produced* and *produced and named differently*:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
11 of 12 months from 2025-01 to 2025-12 — not in this folder: March 2025
|
|
107
|
+
— 1 name here could not be read as any of them: March FINAL v2.csv
|
|
108
|
+
```
|
|
109
|
+
|
|
98
110
|
### `assurance init` — did anything change underneath?
|
|
99
111
|
|
|
100
112
|
```bash
|
|
101
113
|
assurance init ~/thesis-data
|
|
114
|
+
# Baseline written to ~/thesis-data/.assurance.json — 34 tabular files recorded.
|
|
115
|
+
|
|
102
116
|
# ... weeks pass, several people touch the folder ...
|
|
103
117
|
assurance check ~/thesis-data --against-baseline
|
|
104
118
|
```
|
|
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "assurance-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "CLI for folder assurance checks — coverage, staleness, and baselines."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
11
11
|
authors = [{ name = "I-Ops Operations Intelligence, LLC", email = "hello@i-ops.dev" }]
|
|
12
12
|
requires-python = ">=3.10"
|
|
13
13
|
dependencies = [
|
|
14
|
-
"assurance-core>=0.
|
|
14
|
+
"assurance-core>=0.4",
|
|
15
15
|
"openpyxl>=3.1",
|
|
16
16
|
]
|
|
17
17
|
keywords = ["cli", "ai-agents", "governance", "auditing", "assurance", "reproducibility"]
|
|
@@ -154,3 +154,26 @@ def test_the_nested_record_agrees_with_the_wrapper(
|
|
|
154
154
|
def test_a_folder_that_checks_out_still_exits_zero(monthly_folder: Path) -> None:
|
|
155
155
|
"""The counterweight: the ordinary path must not start failing."""
|
|
156
156
|
assert main(["check", str(monthly_folder)]) == 0
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_a_file_named_outside_the_scheme_is_reported_beside_the_gap(tmp_path: Path) -> None:
|
|
160
|
+
"""The case an outside reader described on 2026-08-29: eleven months parse, March is "not in
|
|
161
|
+
this folder", and a file called `March FINAL v2.csv` sits there unmentioned. Knowing a name here
|
|
162
|
+
could not be read is what separates "never produced" from "produced and named differently"."""
|
|
163
|
+
for month in ("01", "02", "04", "05", "06", "07", "08", "09", "10", "11", "12"):
|
|
164
|
+
(tmp_path / f"2025-{month}-report.csv").write_text("a,b\n1,2\n", encoding="utf-8")
|
|
165
|
+
(tmp_path / "March FINAL v2.csv").write_text("a,b\n1,2\n", encoding="utf-8")
|
|
166
|
+
|
|
167
|
+
result = check_coverage(str(tmp_path))
|
|
168
|
+
|
|
169
|
+
assert result["coverage"]["unmatched"] == ["March FINAL v2.csv"]
|
|
170
|
+
assert "could not be read as any of them" in result["summary"]
|
|
171
|
+
assert "March FINAL v2.csv" in result["summary"]
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def test_a_folder_where_everything_parses_reports_nothing_unread(monthly_folder: Path) -> None:
|
|
175
|
+
"""The clause must stay rare enough to mean something."""
|
|
176
|
+
result = check_coverage(str(monthly_folder))
|
|
177
|
+
|
|
178
|
+
assert result["coverage"]["unmatched"] == []
|
|
179
|
+
assert "could not be read" not in result["summary"]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""`__version__` must agree with `pyproject.toml`.
|
|
2
|
+
|
|
3
|
+
Both were hardcoded at "0.1.0" and sat there through five releases, so anyone reading
|
|
4
|
+
`assurance_cli.__version__` was told the wrong thing. Reported by an outside reviewer 2026-08-29.
|
|
5
|
+
|
|
6
|
+
They now read the installed distribution's metadata, which makes `pyproject.toml` the only place a
|
|
7
|
+
version is written. This is the guard that the two agree: CI installs the package immediately before
|
|
8
|
+
running the suite, so the metadata is current there. Locally it can lag a version behind after an
|
|
9
|
+
edit — `pip install -e .` resyncs it, and a lagging editable install is exactly the drift worth
|
|
10
|
+
being told about.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import re
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import assurance_cli
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _declared() -> str:
|
|
22
|
+
text = (Path(__file__).resolve().parent.parent / "pyproject.toml").read_text(encoding="utf-8")
|
|
23
|
+
match = re.search(r'^version = "([^"]+)"', text, re.MULTILINE)
|
|
24
|
+
assert match, "pyproject.toml has no version"
|
|
25
|
+
return match.group(1)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_version_agrees_with_pyproject() -> None:
|
|
29
|
+
assert assurance_cli.__version__ == _declared()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_version_is_not_a_placeholder() -> None:
|
|
33
|
+
assert assurance_cli.__version__ != "0.0.0+unknown"
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"""assurance-cli — folder checks anyone can run without I-Ops.
|
|
2
|
-
|
|
3
|
-
Shared filesystem I/O (`paths`, `profile`, `gather`) lives in this package so `assurance-mcp` can
|
|
4
|
-
import it instead of duplicating the profiler. MCP depends on this package for gathering only; the
|
|
5
|
-
CLI does not depend on MCP. Two copies of the profiler is how they disagree.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
__version__ = "0.1.0"
|
|
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
|