pycode-kg 0.26.0__tar.gz → 0.27.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.
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/PKG-INFO +7 -7
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/README.md +4 -4
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/pyproject.toml +17 -3
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/__init__.py +1 -1
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_init.py +1 -1
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_snapshot.py +30 -2
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/snapshots.py +44 -128
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/LICENSE +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/.DS_Store +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/__main__.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/analysis/__init__.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/analysis/bridge.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/analysis/centrality.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/analysis/framework_detector.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/app.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/architecture.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/build_pycodekg_sqlite.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/__init__.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_analyze.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_architecture.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_bridges.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_build.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_build_full.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_centrality.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_explain.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_framework_nodes.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_hooks.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_mcp.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_model.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_query.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_quilt.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/cmd_viz.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/main.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/cli/options.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/config.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/explain.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/graph.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/graph_html.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/index.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/kg.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/layout3d.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/mcp_server.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/module/__init__.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/module/base.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/module/extractor.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/module/types.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/pycodekg.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/pycodekg_thorough_analysis.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/ranking/__init__.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/ranking/cli_rank.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/ranking/coderank.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/render.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/report.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/resolution.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/scene3d.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/sql/004_add_centrality_table.sql +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/store.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/theme.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/utils.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/visitor.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/viz3d.py +0 -0
- {pycode_kg-0.26.0 → pycode_kg-0.27.0}/src/pycode_kg/viz3d_timeline.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycode-kg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.0
|
|
4
4
|
Summary: A tool to build a searchable knowledge graph from Python repositories
|
|
5
5
|
License-Expression: Elastic-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -21,8 +21,8 @@ Provides-Extra: viz3d
|
|
|
21
21
|
Requires-Dist: PyQt5 (>=5.15.0) ; extra == "all"
|
|
22
22
|
Requires-Dist: PyQt5 (>=5.15.0) ; extra == "viz3d"
|
|
23
23
|
Requires-Dist: click (>=8.1.0,<9)
|
|
24
|
-
Requires-Dist: kgmodule-utils[semantic,viz3d] (>=0.
|
|
25
|
-
Requires-Dist: kgmodule-utils[viz3d-qt,viz3d-render] (>=0.
|
|
24
|
+
Requires-Dist: kgmodule-utils[semantic,viz3d] (>=0.20.0)
|
|
25
|
+
Requires-Dist: kgmodule-utils[viz3d-qt,viz3d-render] (>=0.20.0) ; extra == "viz3d"
|
|
26
26
|
Requires-Dist: markdown (>=3.6) ; extra == "all"
|
|
27
27
|
Requires-Dist: markdown (>=3.6) ; extra == "viz3d"
|
|
28
28
|
Requires-Dist: mcp (>=1.0.0,<2)
|
|
@@ -60,7 +60,7 @@ Description-Content-Type: text/markdown
|
|
|
60
60
|
|
|
61
61
|
[](https://www.python.org/)
|
|
62
62
|
[](https://www.elastic.co/licensing/elastic-license)
|
|
63
|
-
[](https://github.com/Flux-Frontiers/pycode_kg/releases)
|
|
64
64
|
[](https://github.com/Flux-Frontiers/pycode_kg/actions/workflows/ci.yml)
|
|
65
65
|
[](https://python-poetry.org/)
|
|
66
66
|
[](https://zenodo.org/badge/latestdoi/1202379010)
|
|
@@ -255,7 +255,7 @@ src/pycode_kg/
|
|
|
255
255
|
└── viz3d_timeline.py # Metric history timeline
|
|
256
256
|
```
|
|
257
257
|
|
|
258
|
-
The MCP server, the CLI, and the Streamlit app are thin wrappers over the same store + index + ranking core — there is exactly one code path for each capability. The latest architectural deep-dive is in [docs/analysis_v0.
|
|
258
|
+
The MCP server, the CLI, and the Streamlit app are thin wrappers over the same store + index + ranking core — there is exactly one code path for each capability. The latest architectural deep-dive is in [docs/analysis_v0.27.0.md](docs/analysis_v0.27.0.md), produced (of course) by `pycodekg analyze` against this very repo.
|
|
259
259
|
|
|
260
260
|
---
|
|
261
261
|
|
|
@@ -282,13 +282,13 @@ If you use PyCodeKG in your research or project, please cite it:
|
|
|
282
282
|
|
|
283
283
|
[](https://zenodo.org/badge/latestdoi/1202379010)
|
|
284
284
|
|
|
285
|
-
> Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.
|
|
285
|
+
> Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.27.0) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.19737993
|
|
286
286
|
|
|
287
287
|
```bibtex
|
|
288
288
|
@software{suchanek_pycode_kg,
|
|
289
289
|
author = {Suchanek, Eric G.},
|
|
290
290
|
title = {{PyCodeKG}: A Knowledge Graph for Python Codebases},
|
|
291
|
-
version = {0.
|
|
291
|
+
version = {0.27.0},
|
|
292
292
|
year = {2026},
|
|
293
293
|
publisher = {Flux-Frontiers},
|
|
294
294
|
url = {https://github.com/Flux-Frontiers/pycode_kg},
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
[](https://www.python.org/)
|
|
7
7
|
[](https://www.elastic.co/licensing/elastic-license)
|
|
8
|
-
[](https://github.com/Flux-Frontiers/pycode_kg/releases)
|
|
9
9
|
[](https://github.com/Flux-Frontiers/pycode_kg/actions/workflows/ci.yml)
|
|
10
10
|
[](https://python-poetry.org/)
|
|
11
11
|
[](https://zenodo.org/badge/latestdoi/1202379010)
|
|
@@ -200,7 +200,7 @@ src/pycode_kg/
|
|
|
200
200
|
└── viz3d_timeline.py # Metric history timeline
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
-
The MCP server, the CLI, and the Streamlit app are thin wrappers over the same store + index + ranking core — there is exactly one code path for each capability. The latest architectural deep-dive is in [docs/analysis_v0.
|
|
203
|
+
The MCP server, the CLI, and the Streamlit app are thin wrappers over the same store + index + ranking core — there is exactly one code path for each capability. The latest architectural deep-dive is in [docs/analysis_v0.27.0.md](docs/analysis_v0.27.0.md), produced (of course) by `pycodekg analyze` against this very repo.
|
|
204
204
|
|
|
205
205
|
---
|
|
206
206
|
|
|
@@ -227,13 +227,13 @@ If you use PyCodeKG in your research or project, please cite it:
|
|
|
227
227
|
|
|
228
228
|
[](https://zenodo.org/badge/latestdoi/1202379010)
|
|
229
229
|
|
|
230
|
-
> Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.
|
|
230
|
+
> Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.27.0) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.19737993
|
|
231
231
|
|
|
232
232
|
```bibtex
|
|
233
233
|
@software{suchanek_pycode_kg,
|
|
234
234
|
author = {Suchanek, Eric G.},
|
|
235
235
|
title = {{PyCodeKG}: A Knowledge Graph for Python Codebases},
|
|
236
|
-
version = {0.
|
|
236
|
+
version = {0.27.0},
|
|
237
237
|
year = {2026},
|
|
238
238
|
publisher = {Flux-Frontiers},
|
|
239
239
|
url = {https://github.com/Flux-Frontiers/pycode_kg},
|
|
@@ -70,7 +70,7 @@ torch = [
|
|
|
70
70
|
# ---------------------------------------------------------------------------
|
|
71
71
|
[project]
|
|
72
72
|
name = "pycode-kg"
|
|
73
|
-
version = "0.
|
|
73
|
+
version = "0.27.0"
|
|
74
74
|
description = "A tool to build a searchable knowledge graph from Python repositories"
|
|
75
75
|
readme = "README.md"
|
|
76
76
|
license = "Elastic-2.0"
|
|
@@ -155,7 +155,21 @@ dependencies = [
|
|
|
155
155
|
# this repo's visitor writes as of 0.24.1 -- against 0.18.0 the stubs are
|
|
156
156
|
# tagged correctly but the tag is silently ignored, so resolution stays on
|
|
157
157
|
# the old untyped trailing-name match with no error to say so.
|
|
158
|
-
|
|
158
|
+
#
|
|
159
|
+
# 0.19.1 because SnapshotManager.load_snapshot back-fills a missing
|
|
160
|
+
# vs_previous through _compute_delta_from_metrics as of that release.
|
|
161
|
+
# Against 0.19.0 the backfill uses a hardcoded nodes/edges dict, so
|
|
162
|
+
# coverage_delta and critical_issues_delta read as zero in `snapshot show`
|
|
163
|
+
# for every snapshot whose deltas were not persisted at capture -- which is
|
|
164
|
+
# the normal path, not a legacy one.
|
|
165
|
+
#
|
|
166
|
+
# 0.20.0 is a hard requirement, not a preference: snapshots.py has no
|
|
167
|
+
# __init__, capture or diff_snapshots of its own any more. It configures
|
|
168
|
+
# the base through the package_name and dict_metric_deltas class attributes
|
|
169
|
+
# and the _domain_metrics() hook, none of which exist before 0.20.0.
|
|
170
|
+
# Against 0.19.x the manager silently reports itself as "kg-utils" and
|
|
171
|
+
# drops module_node_counts entirely.
|
|
172
|
+
"kgmodule-utils[semantic,viz3d]>=0.20.0",
|
|
159
173
|
]
|
|
160
174
|
|
|
161
175
|
[project.optional-dependencies]
|
|
@@ -180,7 +194,7 @@ viz3d = [
|
|
|
180
194
|
# the four-step build/render/write/cast itself. It subsumes [viz3d-render]
|
|
181
195
|
# (it declares pyvista too), but both are named so the dependency reads as
|
|
182
196
|
# what it is rather than as a side effect.
|
|
183
|
-
"kgmodule-utils[viz3d-render,viz3d-qt]>=0.
|
|
197
|
+
"kgmodule-utils[viz3d-render,viz3d-qt]>=0.20.0",
|
|
184
198
|
"pyvistaqt>=0.11.0",
|
|
185
199
|
"trame-vtk>=2.0.0",
|
|
186
200
|
# Looking Glass quilts. 0.4.0 supplies depth_report() and widened
|
|
@@ -19,6 +19,7 @@ import json
|
|
|
19
19
|
from pathlib import Path
|
|
20
20
|
|
|
21
21
|
import click
|
|
22
|
+
from click.core import ParameterSource
|
|
22
23
|
|
|
23
24
|
from pycode_kg.cli.main import cli
|
|
24
25
|
from pycode_kg.cli.options import sqlite_option
|
|
@@ -34,6 +35,33 @@ from pycode_kg.snapshots import (
|
|
|
34
35
|
from pycode_kg.store import GraphStore
|
|
35
36
|
|
|
36
37
|
|
|
38
|
+
def _graph_for_repo(sqlite: str, repo_root: Path) -> Path:
|
|
39
|
+
"""Resolve the graph path, anchoring the default to ``--repo``.
|
|
40
|
+
|
|
41
|
+
``--sqlite`` defaults to the relative ``.pycodekg/graph.sqlite``, which
|
|
42
|
+
click resolves against the *current working directory*, while
|
|
43
|
+
``--repo`` decides where the snapshot is filed. Left alone, the two
|
|
44
|
+
disagree: ``pycodekg snapshot save 1.0.0 --repo /other/project`` run from
|
|
45
|
+
inside this repo reads *this* repo's graph and writes the result into
|
|
46
|
+
*/other/project*'s snapshots directory -- a snapshot whose metrics belong
|
|
47
|
+
to one project and whose provenance claims another, with no error.
|
|
48
|
+
|
|
49
|
+
An explicitly passed ``--sqlite`` is always honoured as given; only the
|
|
50
|
+
default is re-anchored. The other commands sharing ``sqlite_option``
|
|
51
|
+
(``query``, ``explain``) take no ``--repo``, so cwd is the right base for
|
|
52
|
+
them and they are unaffected.
|
|
53
|
+
|
|
54
|
+
:param sqlite: The ``--sqlite`` value, explicit or default.
|
|
55
|
+
:param repo_root: The resolved ``--repo`` path.
|
|
56
|
+
:return: The graph database path to read.
|
|
57
|
+
"""
|
|
58
|
+
ctx = click.get_current_context(silent=True)
|
|
59
|
+
source = ctx.get_parameter_source("sqlite") if ctx is not None else None
|
|
60
|
+
if source is not None and source is not ParameterSource.DEFAULT:
|
|
61
|
+
return Path(sqlite)
|
|
62
|
+
return repo_root / ".pycodekg" / "graph.sqlite"
|
|
63
|
+
|
|
64
|
+
|
|
37
65
|
@cli.group("snapshot")
|
|
38
66
|
def snapshot() -> None:
|
|
39
67
|
"""Manage temporal snapshots of PyCodeKG metrics."""
|
|
@@ -105,7 +133,7 @@ def save_snapshot(
|
|
|
105
133
|
pycodekg snapshot save 0.5.1 --repo .
|
|
106
134
|
"""
|
|
107
135
|
repo_root = Path(repo).resolve()
|
|
108
|
-
db_path =
|
|
136
|
+
db_path = _graph_for_repo(sqlite, repo_root)
|
|
109
137
|
snapshots_path = (
|
|
110
138
|
Path(snapshots_dir).resolve() if snapshots_dir else (repo_root / ".pycodekg" / "snapshots")
|
|
111
139
|
)
|
|
@@ -161,7 +189,7 @@ def save_snapshot(
|
|
|
161
189
|
version=version,
|
|
162
190
|
branch=branch,
|
|
163
191
|
graph_stats_dict=stats,
|
|
164
|
-
|
|
192
|
+
docstring_coverage=coverage,
|
|
165
193
|
coverage_documented=coverage_documented,
|
|
166
194
|
coverage_total=coverage_total,
|
|
167
195
|
critical_issues=critical_issues,
|
|
@@ -15,7 +15,7 @@ This module adds:
|
|
|
15
15
|
``metrics_from_dict`` / ``metrics_to_dict`` and ``delta_from_dict`` /
|
|
16
16
|
``delta_to_dict``; a ``Snapshot`` never holds one.
|
|
17
17
|
- a ``SnapshotManager`` subclass that sets ``package_name="pycode-kg"``,
|
|
18
|
-
|
|
18
|
+
collects the pycode-kg metric fields in ``_domain_metrics()``, adds
|
|
19
19
|
``coverage_delta`` and ``critical_issues_delta`` to deltas, collects
|
|
20
20
|
per-module node counts from SQLite, and extends a diff with
|
|
21
21
|
``module_node_counts_delta``, ``issues_delta`` and ``timestamp``.
|
|
@@ -44,7 +44,6 @@ from __future__ import annotations
|
|
|
44
44
|
|
|
45
45
|
import sqlite3
|
|
46
46
|
from dataclasses import dataclass, field
|
|
47
|
-
from pathlib import Path
|
|
48
47
|
from typing import Any
|
|
49
48
|
|
|
50
49
|
# ---------------------------------------------------------------------------
|
|
@@ -174,147 +173,64 @@ def delta_from_dict(d: dict[str, Any] | None) -> SnapshotDelta | None:
|
|
|
174
173
|
class SnapshotManager(_BaseSnapshotManager):
|
|
175
174
|
"""pycode-kg snapshot manager.
|
|
176
175
|
|
|
177
|
-
Subclasses the shared ``kg_utils.snapshots.SnapshotManager
|
|
176
|
+
Subclasses the shared ``kg_utils.snapshots.SnapshotManager``. Three of the
|
|
177
|
+
four additions are class attributes rather than methods, because the base
|
|
178
|
+
supplies the behaviour and this module only names the domain values:
|
|
178
179
|
|
|
179
|
-
* ``package_name="pycode-kg"``
|
|
180
|
-
*
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
* ``package_name = "pycode-kg"`` for version detection.
|
|
181
|
+
* ``dict_metric_deltas`` naming ``module_node_counts``, which the base
|
|
182
|
+
turns into ``module_node_counts_delta`` in ``diff_snapshots``.
|
|
183
|
+
* ``_domain_metrics()`` collecting per-module node counts at capture time.
|
|
183
184
|
* ``_compute_delta_from_metrics`` extended with ``coverage_delta`` and
|
|
184
|
-
``critical_issues_delta
|
|
185
|
-
* ``diff_snapshots`` extended with ``module_node_counts_delta``,
|
|
186
|
-
``issues_delta`` and ``timestamp``.
|
|
185
|
+
``critical_issues_delta`` — the one genuinely domain-specific method.
|
|
187
186
|
* ``_collect_module_node_counts()`` — SQLite per-module node counts.
|
|
188
187
|
|
|
189
|
-
Everything else -- saving, loading, listing, pruning, key
|
|
190
|
-
inherited unchanged.
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
Everything else -- capture, saving, loading, listing, pruning, diffing, key
|
|
189
|
+
handling -- is inherited unchanged. Overriding those is what this module
|
|
190
|
+
used to do, and is what let the 0.25.0 snapshot key regression through.
|
|
191
|
+
|
|
192
|
+
Note that ``capture()`` takes the coverage fraction as
|
|
193
|
+
``docstring_coverage``, the name it is stored under. Until 0.27.0 this
|
|
194
|
+
class overrode ``capture()`` to accept it as ``coverage`` and rename it on
|
|
195
|
+
the way through; that override is gone, and with it the signature-restating
|
|
196
|
+
pattern that let a ``key=`` go missing. ``coverage=`` still works and warns
|
|
197
|
+
-- see ``capture_aliases`` below.
|
|
193
198
|
"""
|
|
194
199
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
snapshots_dir: Path | str,
|
|
198
|
-
*,
|
|
199
|
-
db_path: Path | str | None = None,
|
|
200
|
-
package_name: str = "pycode-kg",
|
|
201
|
-
) -> None:
|
|
202
|
-
"""Initialize the manager rooted at ``snapshots_dir``.
|
|
203
|
-
|
|
204
|
-
:param snapshots_dir: Directory where snapshot JSON files live; created
|
|
205
|
-
on first save if it does not exist.
|
|
206
|
-
:param db_path: PyCodeKG SQLite graph path; required for collecting
|
|
207
|
-
per-module node counts during ``capture()``. Optional otherwise.
|
|
208
|
-
:param package_name: Package name used for version detection in saved
|
|
209
|
-
snapshots. Defaults to ``"pycode-kg"``.
|
|
210
|
-
"""
|
|
211
|
-
super().__init__(snapshots_dir, package_name=package_name, db_path=db_path)
|
|
200
|
+
#: Version detection reads this; the base uses it as the snapshot's ``tool``.
|
|
201
|
+
package_name = "pycode-kg"
|
|
212
202
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
203
|
+
#: ``diff_snapshots`` emits ``module_node_counts_delta`` from this, holding
|
|
204
|
+
#: only the modules whose node count actually changed.
|
|
205
|
+
dict_metric_deltas = ("module_node_counts",)
|
|
216
206
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
coverage_total: int = 0,
|
|
225
|
-
critical_issues: int = 0,
|
|
226
|
-
complexity_median: float = 0.0,
|
|
227
|
-
hotspots: list[dict[str, Any]] | None = None,
|
|
228
|
-
issues: list[str] | None = None,
|
|
229
|
-
tree_hash: str = "",
|
|
230
|
-
key: str = "",
|
|
231
|
-
subject: str = "",
|
|
232
|
-
) -> Snapshot:
|
|
233
|
-
"""Capture a pycode-kg snapshot.
|
|
234
|
-
|
|
235
|
-
Names the pycode-kg metric fields explicitly rather than taking them
|
|
236
|
-
through ``**extra_metrics``, and adds per-module node counts, then
|
|
237
|
-
delegates to the shared implementation.
|
|
238
|
-
|
|
239
|
-
:param version: Version string (e.g., "0.5.1").
|
|
240
|
-
:param branch: Git branch name; auto-detected if None.
|
|
241
|
-
:param graph_stats_dict: Output from ``graph_stats()`` / ``store.stats()``.
|
|
242
|
-
:param coverage: Docstring coverage fraction (0.0-1.0).
|
|
243
|
-
:param coverage_documented: Nodes with a non-empty docstring — the
|
|
244
|
-
numerator behind ``coverage``. Shown beside the percentage in
|
|
245
|
-
Snapshot History so a coverage drop caused by adding undocumented
|
|
246
|
-
nodes reads differently from one caused by removing docstrings.
|
|
247
|
-
:param coverage_total: Nodes eligible for docstring coverage — the
|
|
248
|
-
denominator behind ``coverage``.
|
|
249
|
-
:param critical_issues: Number of critical issues detected.
|
|
250
|
-
:param complexity_median: Median fan-in across functions.
|
|
251
|
-
:param hotspots: Top hotspot entries.
|
|
252
|
-
:param issues: Issue description strings.
|
|
253
|
-
:param tree_hash: Git tree hash, recorded as provenance; auto-detected
|
|
254
|
-
if not provided. It is not the snapshot's key.
|
|
255
|
-
:param key: Snapshot identifier. Pass the release tag at release time;
|
|
256
|
-
omit it and the base assigns a UTC timestamp.
|
|
257
|
-
:param subject: What was measured, e.g. ``repo:pycode-kg``.
|
|
258
|
-
:return: New :class:`~kg_utils.snapshots.Snapshot` (not yet persisted).
|
|
259
|
-
"""
|
|
260
|
-
return super().capture(
|
|
261
|
-
version=version,
|
|
262
|
-
branch=branch,
|
|
263
|
-
graph_stats_dict=graph_stats_dict,
|
|
264
|
-
tree_hash=tree_hash,
|
|
265
|
-
key=key,
|
|
266
|
-
subject=subject,
|
|
267
|
-
hotspots=hotspots,
|
|
268
|
-
issues=issues,
|
|
269
|
-
docstring_coverage=coverage,
|
|
270
|
-
coverage_documented=coverage_documented,
|
|
271
|
-
coverage_total=coverage_total,
|
|
272
|
-
critical_issues=critical_issues,
|
|
273
|
-
complexity_median=complexity_median,
|
|
274
|
-
module_node_counts=self._collect_module_node_counts(),
|
|
275
|
-
)
|
|
207
|
+
#: Until 0.27.0 this class overrode ``capture()`` to accept the docstring
|
|
208
|
+
#: coverage fraction as ``coverage`` and rename it on the way through. The
|
|
209
|
+
#: override is gone, and the stored name is the only name. Without this
|
|
210
|
+
#: entry a caller still passing ``coverage=`` would get no error: the base
|
|
211
|
+
#: ``**extra_metrics`` would record a ``coverage`` metric nobody reads and
|
|
212
|
+
#: leave ``docstring_coverage`` absent.
|
|
213
|
+
capture_aliases = {"coverage": "docstring_coverage"}
|
|
276
214
|
|
|
277
215
|
# ------------------------------------------------------------------
|
|
278
|
-
#
|
|
216
|
+
# Capture-time metrics collected by this module
|
|
279
217
|
# ------------------------------------------------------------------
|
|
280
218
|
|
|
281
|
-
def
|
|
282
|
-
"""
|
|
219
|
+
def _domain_metrics(self, stats: dict[str, Any]) -> dict[str, Any]:
|
|
220
|
+
"""Collect the metrics this module gathers for itself.
|
|
283
221
|
|
|
284
|
-
|
|
285
|
-
``
|
|
286
|
-
|
|
222
|
+
Called by the inherited ``capture()``. Overriding this rather than
|
|
223
|
+
``capture()`` is deliberate: a ``capture()`` override has to restate the
|
|
224
|
+
base signature, and restating it is what let ``key=`` fall into
|
|
225
|
+
``**extra_metrics`` and ship 0.25.0 with every snapshot keyed on a tree
|
|
226
|
+
hash.
|
|
287
227
|
|
|
288
|
-
:param
|
|
289
|
-
|
|
290
|
-
:return:
|
|
228
|
+
:param stats: Graph stats passed to ``capture()``; unused here, the
|
|
229
|
+
counts come from SQLite.
|
|
230
|
+
:return: ``{"module_node_counts": {module_path: node_count}}``, empty
|
|
231
|
+
if no SQLite graph is configured.
|
|
291
232
|
"""
|
|
292
|
-
|
|
293
|
-
if "error" in result:
|
|
294
|
-
return result
|
|
295
|
-
|
|
296
|
-
for side, key in (("a", key_a), ("b", key_b)):
|
|
297
|
-
snap = self.load_snapshot(key)
|
|
298
|
-
if snap is not None:
|
|
299
|
-
result[side]["timestamp"] = snap.timestamp
|
|
300
|
-
|
|
301
|
-
m_a: dict[str, Any] = result["a"]["metrics"]
|
|
302
|
-
m_b: dict[str, Any] = result["b"]["metrics"]
|
|
303
|
-
counts_a: dict[str, int] = m_a.get("module_node_counts", {})
|
|
304
|
-
counts_b: dict[str, int] = m_b.get("module_node_counts", {})
|
|
305
|
-
result["module_node_counts_delta"] = {
|
|
306
|
-
mod: counts_b.get(mod, 0) - counts_a.get(mod, 0)
|
|
307
|
-
for mod in set(counts_a) | set(counts_b)
|
|
308
|
-
if counts_b.get(mod, 0) != counts_a.get(mod, 0)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
issues_a = set(result["a"]["issues"])
|
|
312
|
-
issues_b = set(result["b"]["issues"])
|
|
313
|
-
result["issues_delta"] = {
|
|
314
|
-
"introduced": list(issues_b - issues_a),
|
|
315
|
-
"resolved": list(issues_a - issues_b),
|
|
316
|
-
}
|
|
317
|
-
return result
|
|
233
|
+
return {"module_node_counts": self._collect_module_node_counts()}
|
|
318
234
|
|
|
319
235
|
# ------------------------------------------------------------------
|
|
320
236
|
# Delta computation — adds coverage_delta and critical_issues_delta
|
|
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
|
|
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
|