pycode-kg 0.28.0__tar.gz → 0.28.1__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.28.0 → pycode_kg-0.28.1}/PKG-INFO +5 -5
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/README.md +4 -4
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/pyproject.toml +1 -1
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/__init__.py +1 -1
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/pycodekg_thorough_analysis.py +33 -1
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/report.py +29 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/LICENSE +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/.DS_Store +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/__main__.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/analysis/__init__.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/analysis/bridge.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/analysis/centrality.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/analysis/framework_detector.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/app.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/architecture.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/build_pycodekg_sqlite.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/__init__.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_analyze.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_architecture.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_bridges.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_build.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_build_full.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_centrality.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_explain.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_framework_nodes.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_hooks.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_init.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_mcp.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_model.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_query.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_quilt.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_snapshot.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/cmd_viz.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/main.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/cli/options.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/config.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/explain.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/graph.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/graph_html.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/index.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/kg.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/layout3d.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/mcp_server.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/module/__init__.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/module/base.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/module/extractor.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/module/types.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/pycodekg.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/ranking/__init__.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/ranking/cli_rank.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/ranking/coderank.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/render.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/resolution.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/scene3d.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/snapshots.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/sql/004_add_centrality_table.sql +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/store.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/theme.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/utils.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/visitor.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/src/pycode_kg/viz3d.py +0 -0
- {pycode_kg-0.28.0 → pycode_kg-0.28.1}/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.28.
|
|
3
|
+
Version: 0.28.1
|
|
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
|
|
@@ -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://doi.org/10.5281/zenodo.19737993)
|
|
@@ -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.28.
|
|
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.28.1.md](docs/analysis_v0.28.1.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://doi.org/10.5281/zenodo.19737993)
|
|
284
284
|
|
|
285
|
-
> Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.28.
|
|
285
|
+
> Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.28.1) [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.28.
|
|
291
|
+
version = {0.28.1},
|
|
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://doi.org/10.5281/zenodo.19737993)
|
|
@@ -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.28.
|
|
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.28.1.md](docs/analysis_v0.28.1.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://doi.org/10.5281/zenodo.19737993)
|
|
229
229
|
|
|
230
|
-
> Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.28.
|
|
230
|
+
> Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.28.1) [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.28.
|
|
236
|
+
version = {0.28.1},
|
|
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.28.
|
|
73
|
+
version = "0.28.1"
|
|
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"
|
|
@@ -43,6 +43,7 @@ from collections.abc import Callable
|
|
|
43
43
|
from dataclasses import asdict, dataclass
|
|
44
44
|
from pathlib import Path
|
|
45
45
|
|
|
46
|
+
from kg_utils.vector_backend import VectorStoreNotFoundError
|
|
46
47
|
from rich.columns import Columns
|
|
47
48
|
from rich.console import Console
|
|
48
49
|
from rich.panel import Panel
|
|
@@ -444,6 +445,8 @@ class PyCodeKGAnalyzer:
|
|
|
444
445
|
self.concern_analysis: list[dict] = [] # populated by _analyze_concerns
|
|
445
446
|
# Single-line phase output: each phase fn writes its summary here
|
|
446
447
|
self._phase_result: str = ""
|
|
448
|
+
# Phases that raised; rendered in the report (see _run_phase)
|
|
449
|
+
self.phase_failures: list[dict] = []
|
|
447
450
|
|
|
448
451
|
# ── total phase count (update if phases are added/removed) ────────────────
|
|
449
452
|
_TOTAL_PHASES = 15
|
|
@@ -455,13 +458,39 @@ class PyCodeKGAnalyzer:
|
|
|
455
458
|
instead of printing directly, keeping the terminal output to one line
|
|
456
459
|
per phase.
|
|
457
460
|
|
|
461
|
+
A phase that cannot run must not take the others and the report with
|
|
462
|
+
it. The concrete case is ``pycodekg build-sqlite``, a supported command
|
|
463
|
+
that builds the graph without the vector index: the fan-out and
|
|
464
|
+
concern-ranking phases seed on a semantic query and raise
|
|
465
|
+
``VectorStoreNotFoundError``, while every other phase reads the graph
|
|
466
|
+
only. The failure is recorded in :attr:`phase_failures` and rendered in
|
|
467
|
+
the report, so a degraded run names its missing sections instead of
|
|
468
|
+
quietly omitting them.
|
|
469
|
+
|
|
458
470
|
:param num: Phase number (1-based).
|
|
459
471
|
:param name: Human-readable phase label.
|
|
460
472
|
:param fn: Zero-argument callable to execute.
|
|
461
473
|
"""
|
|
462
474
|
self._phase_result = ""
|
|
463
475
|
t0 = time.monotonic()
|
|
464
|
-
|
|
476
|
+
try:
|
|
477
|
+
fn()
|
|
478
|
+
except Exception as exc: # noqa: BLE001 -- see docstring
|
|
479
|
+
elapsed = time.monotonic() - t0
|
|
480
|
+
self.phase_failures.append(
|
|
481
|
+
{
|
|
482
|
+
"phase": num,
|
|
483
|
+
"name": name,
|
|
484
|
+
"error": str(exc),
|
|
485
|
+
"missing_index": isinstance(exc, VectorStoreNotFoundError),
|
|
486
|
+
}
|
|
487
|
+
)
|
|
488
|
+
logger.warning("Phase %d (%s) failed: %s", num, name, exc)
|
|
489
|
+
self.console.print(
|
|
490
|
+
f" [cyan]▶ Phase {num:2d}/{self._TOTAL_PHASES}:[/cyan]"
|
|
491
|
+
f" {name} [yellow]skipped: {exc}[/yellow] [green]({elapsed:.1f}s)[/green]"
|
|
492
|
+
)
|
|
493
|
+
return
|
|
465
494
|
elapsed = time.monotonic() - t0
|
|
466
495
|
result = f" {self._phase_result}" if self._phase_result else ""
|
|
467
496
|
self.console.print(
|
|
@@ -2505,6 +2534,9 @@ class PyCodeKGAnalyzer:
|
|
|
2505
2534
|
"coderank_top_nodes": self.coderank_top_nodes,
|
|
2506
2535
|
# Option D: concern-based hybrid ranking
|
|
2507
2536
|
"concern_analysis": self.concern_analysis,
|
|
2537
|
+
# An empty section above may mean a phase did not run, not that
|
|
2538
|
+
# the codebase has nothing to show.
|
|
2539
|
+
"phase_failures": self.phase_failures,
|
|
2508
2540
|
}
|
|
2509
2541
|
|
|
2510
2542
|
def to_markdown(self, *, metadata: str = "", elapsed_seconds: float | None = None) -> str:
|
|
@@ -124,6 +124,35 @@ def render_markdown(analyzer, *, metadata: str = "", elapsed_seconds: float | No
|
|
|
124
124
|
out += [f"# {repo_name} Analysis", "", f"**Generated:** {generated}"]
|
|
125
125
|
rule()
|
|
126
126
|
|
|
127
|
+
# ── Incomplete Analysis ──────────────────────────────────────────────
|
|
128
|
+
# A phase that could not run leaves its section empty. Said plainly, that
|
|
129
|
+
# is a missing build step; left unsaid, it reads as a finding about the code.
|
|
130
|
+
failures = analyzer.phase_failures
|
|
131
|
+
if failures:
|
|
132
|
+
out += [
|
|
133
|
+
"## Incomplete Analysis",
|
|
134
|
+
"",
|
|
135
|
+
f"{len(failures)} of {analyzer._TOTAL_PHASES} phases could not run. "
|
|
136
|
+
"The sections they produce are missing from this report -- that is a "
|
|
137
|
+
"gap in the analysis, not a finding about the code.",
|
|
138
|
+
"",
|
|
139
|
+
]
|
|
140
|
+
out += md_table(
|
|
141
|
+
["Phase", "Name", "Reason"],
|
|
142
|
+
[(f["phase"], f["name"], f"`{f['error']}`") for f in failures],
|
|
143
|
+
aligns="rll",
|
|
144
|
+
)
|
|
145
|
+
if any(f["missing_index"] for f in failures):
|
|
146
|
+
out += [
|
|
147
|
+
"",
|
|
148
|
+
"> The semantic index is missing. Only the fan-out and concern-based "
|
|
149
|
+
"ranking phases need it; every other phase reads the SQLite graph "
|
|
150
|
+
"directly, which is why the rest of this report is complete. Run "
|
|
151
|
+
"`pycodekg build-index` (or `pycodekg build`) to build it, then "
|
|
152
|
+
"re-run the analysis.",
|
|
153
|
+
]
|
|
154
|
+
rule()
|
|
155
|
+
|
|
127
156
|
# ── Executive Summary ────────────────────────────────────────────────
|
|
128
157
|
out += [
|
|
129
158
|
"## Executive Summary",
|
|
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
|
|
File without changes
|