pycode-kg 0.24.1__tar.gz → 0.25.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.
Files changed (62) hide show
  1. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/PKG-INFO +7 -7
  2. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/README.md +5 -5
  3. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/pyproject.toml +2 -2
  4. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/__init__.py +1 -1
  5. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_snapshot.py +24 -5
  6. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/snapshots.py +19 -15
  7. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/LICENSE +0 -0
  8. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/.DS_Store +0 -0
  9. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/__main__.py +0 -0
  10. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/analysis/__init__.py +0 -0
  11. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/analysis/bridge.py +0 -0
  12. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/analysis/centrality.py +0 -0
  13. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/analysis/framework_detector.py +0 -0
  14. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/app.py +0 -0
  15. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/architecture.py +0 -0
  16. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/build_pycodekg_sqlite.py +0 -0
  17. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/__init__.py +0 -0
  18. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_analyze.py +0 -0
  19. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_architecture.py +0 -0
  20. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_bridges.py +0 -0
  21. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_build.py +0 -0
  22. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_build_full.py +0 -0
  23. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_centrality.py +0 -0
  24. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_explain.py +0 -0
  25. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_framework_nodes.py +0 -0
  26. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_hooks.py +0 -0
  27. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_init.py +0 -0
  28. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_mcp.py +0 -0
  29. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_model.py +0 -0
  30. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_query.py +0 -0
  31. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_quilt.py +0 -0
  32. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/cmd_viz.py +0 -0
  33. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/main.py +0 -0
  34. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/cli/options.py +0 -0
  35. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/config.py +0 -0
  36. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/explain.py +0 -0
  37. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/graph.py +0 -0
  38. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/graph_html.py +0 -0
  39. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/index.py +0 -0
  40. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/kg.py +0 -0
  41. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/layout3d.py +0 -0
  42. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/mcp_server.py +0 -0
  43. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/module/__init__.py +0 -0
  44. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/module/base.py +0 -0
  45. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/module/extractor.py +0 -0
  46. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/module/types.py +0 -0
  47. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/pycodekg.py +0 -0
  48. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/pycodekg_thorough_analysis.py +0 -0
  49. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/ranking/__init__.py +0 -0
  50. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/ranking/cli_rank.py +0 -0
  51. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/ranking/coderank.py +0 -0
  52. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/render.py +0 -0
  53. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/report.py +0 -0
  54. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/resolution.py +0 -0
  55. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/scene3d.py +0 -0
  56. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/sql/004_add_centrality_table.sql +0 -0
  57. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/store.py +0 -0
  58. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/theme.py +0 -0
  59. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/utils.py +0 -0
  60. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/visitor.py +0 -0
  61. {pycode_kg-0.24.1 → pycode_kg-0.25.1}/src/pycode_kg/viz3d.py +0 -0
  62. {pycode_kg-0.24.1 → pycode_kg-0.25.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.24.1
3
+ Version: 0.25.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
@@ -21,7 +21,7 @@ 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.18.1)
24
+ Requires-Dist: kgmodule-utils[semantic,viz3d] (>=0.19.0)
25
25
  Requires-Dist: kgmodule-utils[viz3d-qt,viz3d-render] (>=0.18.1) ; extra == "viz3d"
26
26
  Requires-Dist: markdown (>=3.6) ; extra == "all"
27
27
  Requires-Dist: markdown (>=3.6) ; extra == "viz3d"
@@ -60,7 +60,7 @@ Description-Content-Type: text/markdown
60
60
 
61
61
  [![Python](https://img.shields.io/badge/python-3.12%20%7C%203.13-blue.svg)](https://www.python.org/)
62
62
  [![License: Elastic-2.0](https://img.shields.io/badge/License-Elastic%202.0-blue.svg)](https://www.elastic.co/licensing/elastic-license)
63
- [![Version](https://img.shields.io/badge/version-0.24.1-blue.svg)](https://github.com/Flux-Frontiers/pycode_kg/releases)
63
+ [![Version](https://img.shields.io/badge/version-0.25.1-blue.svg)](https://github.com/Flux-Frontiers/pycode_kg/releases)
64
64
  [![CI](https://github.com/Flux-Frontiers/pycode_kg/actions/workflows/ci.yml/badge.svg)](https://github.com/Flux-Frontiers/pycode_kg/actions/workflows/ci.yml)
65
65
  [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
66
66
  [![DOI](https://zenodo.org/badge/1202379010.svg)](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.24.1.md](docs/analysis_v0.24.1.md), produced (of course) by `pycodekg analyze` against this very repo.
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.25.1.md](docs/analysis_v0.25.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
  [![DOI](https://zenodo.org/badge/1202379010.svg)](https://zenodo.org/badge/latestdoi/1202379010)
284
284
 
285
- > Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.24.1) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.19737993
285
+ > Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.25.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.24.1},
291
+ version = {0.25.1},
292
292
  year = {2026},
293
293
  publisher = {Flux-Frontiers},
294
294
  url = {https://github.com/Flux-Frontiers/pycode_kg},
@@ -312,5 +312,5 @@ If you use PyCodeKG in your research or project, please cite it:
312
312
 
313
313
  ---
314
314
 
315
- *Built for Python developers and AI agents that work alongside them — egs · Last updated August 2026*
315
+ *Built for Python developers and AI agents that work alongside them — egs*
316
316
 
@@ -5,7 +5,7 @@
5
5
 
6
6
  [![Python](https://img.shields.io/badge/python-3.12%20%7C%203.13-blue.svg)](https://www.python.org/)
7
7
  [![License: Elastic-2.0](https://img.shields.io/badge/License-Elastic%202.0-blue.svg)](https://www.elastic.co/licensing/elastic-license)
8
- [![Version](https://img.shields.io/badge/version-0.24.1-blue.svg)](https://github.com/Flux-Frontiers/pycode_kg/releases)
8
+ [![Version](https://img.shields.io/badge/version-0.25.1-blue.svg)](https://github.com/Flux-Frontiers/pycode_kg/releases)
9
9
  [![CI](https://github.com/Flux-Frontiers/pycode_kg/actions/workflows/ci.yml/badge.svg)](https://github.com/Flux-Frontiers/pycode_kg/actions/workflows/ci.yml)
10
10
  [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
11
11
  [![DOI](https://zenodo.org/badge/1202379010.svg)](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.24.1.md](docs/analysis_v0.24.1.md), produced (of course) by `pycodekg analyze` against this very repo.
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.25.1.md](docs/analysis_v0.25.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
  [![DOI](https://zenodo.org/badge/1202379010.svg)](https://zenodo.org/badge/latestdoi/1202379010)
229
229
 
230
- > Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.24.1) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.19737993
230
+ > Suchanek, E. G. (2026). *PyCodeKG: A Knowledge Graph for Python Codebases* (Version 0.25.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.24.1},
236
+ version = {0.25.1},
237
237
  year = {2026},
238
238
  publisher = {Flux-Frontiers},
239
239
  url = {https://github.com/Flux-Frontiers/pycode_kg},
@@ -257,4 +257,4 @@ If you use PyCodeKG in your research or project, please cite it:
257
257
 
258
258
  ---
259
259
 
260
- *Built for Python developers and AI agents that work alongside them — egs · Last updated August 2026*
260
+ *Built for Python developers and AI agents that work alongside them — egs*
@@ -70,7 +70,7 @@ torch = [
70
70
  # ---------------------------------------------------------------------------
71
71
  [project]
72
72
  name = "pycode-kg"
73
- version = "0.24.1"
73
+ version = "0.25.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"
@@ -155,7 +155,7 @@ 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
- "kgmodule-utils[semantic,viz3d]>=0.18.1",
158
+ "kgmodule-utils[semantic,viz3d]>=0.19.0",
159
159
  ]
160
160
 
161
161
  [project.optional-dependencies]
@@ -36,7 +36,7 @@ Author: Eric G. Suchanek, PhD
36
36
  License: Elastic 2.0
37
37
  """
38
38
 
39
- __version__ = "0.24.1"
39
+ __version__ = "0.25.1"
40
40
  __author__ = "Eric G. Suchanek, PhD"
41
41
 
42
42
  # Low-level primitives (locked v0 contract)
@@ -61,7 +61,13 @@ def snapshot() -> None:
61
61
  "--tree-hash",
62
62
  default="",
63
63
  type=str,
64
- help="Git tree hash; auto-detected if not provided.",
64
+ help="Git tree hash, recorded as provenance; auto-detected if not provided.",
65
+ )
66
+ @click.option(
67
+ "--subject",
68
+ default="",
69
+ type=str,
70
+ help="What was measured, e.g. 'repo:pycode-kg' or 'corpus:pepys'.",
65
71
  )
66
72
  def save_snapshot(
67
73
  version: str | None,
@@ -70,16 +76,25 @@ def save_snapshot(
70
76
  snapshots_dir: str | None,
71
77
  branch: str | None,
72
78
  tree_hash: str,
79
+ subject: str,
73
80
  ) -> None:
74
81
  """
75
82
  Capture current PyCodeKG metrics and save as a temporal snapshot.
76
83
 
77
84
  Reads graph statistics, docstring coverage, and complexity metrics from
78
- the SQLite graph, then saves a snapshot tagged with the given VERSION.
79
- The tree hash is auto-detected from git when not provided.
85
+ the SQLite graph, then saves a snapshot keyed on VERSION.
86
+
87
+ **Pass VERSION explicitly at release time.** An omitted VERSION is
88
+ auto-detected from the installed pycode-kg package, which names the
89
+ measuring tool rather than the repo being measured -- in any repo other
90
+ than this one that is the wrong number, so it is recorded as the version
91
+ but never used as the key. Omitting it keys the snapshot on a UTC
92
+ timestamp instead, which is the right answer for a corpus.
80
93
 
81
- Snapshots are stored in .pycodekg/snapshots/{tree_hash}.json, with a
82
- manifest.json tracking all snapshots and their metrics.
94
+ Snapshots are stored in .pycodekg/snapshots/{key}.json, with a
95
+ manifest.json tracking all snapshots and their metrics. The git tree hash
96
+ is recorded as provenance and is no longer the key: it is read before
97
+ `git add` stages the snapshot, so it names a tree that is never committed.
83
98
 
84
99
  Example:
85
100
  pycodekg snapshot save 0.5.1 --repo .
@@ -149,6 +164,10 @@ def save_snapshot(
149
164
  hotspots=hotspots,
150
165
  issues=issue_strings,
151
166
  tree_hash=tree_hash,
167
+ # An explicit VERSION is a release tag and becomes the key. An
168
+ # auto-detected one is the measuring tool's version and must not be.
169
+ key=version or "",
170
+ subject=subject or "",
152
171
  )
153
172
 
154
173
  snapshot_file = snap_mgr.save_snapshot(snapshot_obj)
@@ -181,6 +181,12 @@ class Snapshot(_BaseSnapshot):
181
181
  The underlying ``metrics``, ``vs_previous``, and ``vs_baseline`` fields
182
182
  remain plain dicts on disk; the properties are view-only adapters.
183
183
 
184
+ ``to_dict`` is **not** overridden. The base reads those three fields out of
185
+ ``__dict__`` rather than through these properties (kgmodule-utils 0.19.0),
186
+ which is what the override used to exist for -- and the base is also what
187
+ supplies the current key scheme, so an override here would silently keep
188
+ writing tree-hash keys.
189
+
184
190
  Implementation note
185
191
  -------------------
186
192
  Python dataclass fields are stored in ``__dict__`` under their field name.
@@ -225,20 +231,6 @@ class Snapshot(_BaseSnapshot):
225
231
  else:
226
232
  self.__dict__["vs_baseline"] = value
227
233
 
228
- def to_dict(self) -> dict[str, Any]:
229
- """Convert snapshot to a JSON-serializable dictionary."""
230
- return {
231
- "key": self.tree_hash,
232
- "branch": self.branch,
233
- "timestamp": self.timestamp,
234
- "version": self.version,
235
- "metrics": self.__dict__["metrics"],
236
- "hotspots": self.hotspots,
237
- "issues": self.issues,
238
- "vs_previous": self.__dict__["vs_previous"],
239
- "vs_baseline": self.__dict__["vs_baseline"],
240
- }
241
-
242
234
  @staticmethod
243
235
  def from_dict(data: dict[str, Any]) -> Snapshot: # type: ignore[override]
244
236
  """Reconstruct a pycode-kg ``Snapshot`` from a dictionary."""
@@ -302,6 +294,8 @@ class SnapshotManager(_BaseSnapshotManager):
302
294
  hotspots: list[dict[str, Any]] | None = None,
303
295
  issues: list[str] | None = None,
304
296
  tree_hash: str = "",
297
+ key: str = "",
298
+ subject: str = "",
305
299
  ) -> Snapshot:
306
300
  """Capture a pycode-kg snapshot.
307
301
 
@@ -324,7 +318,11 @@ class SnapshotManager(_BaseSnapshotManager):
324
318
  :param complexity_median: Median fan-in across functions.
325
319
  :param hotspots: Top hotspot entries.
326
320
  :param issues: Issue description strings.
327
- :param tree_hash: Git tree hash; auto-detected if not provided.
321
+ :param tree_hash: Git tree hash, recorded as provenance; auto-detected
322
+ if not provided. It is not the snapshot's key.
323
+ :param key: Snapshot identifier. Pass the release tag at release time;
324
+ omit it and the base assigns a UTC timestamp.
325
+ :param subject: What was measured, e.g. ``repo:pycode-kg``.
328
326
  :return: New :class:`Snapshot` instance (not yet persisted).
329
327
  """
330
328
  module_node_counts = self._collect_module_node_counts()
@@ -334,6 +332,8 @@ class SnapshotManager(_BaseSnapshotManager):
334
332
  branch=branch,
335
333
  graph_stats_dict=graph_stats_dict,
336
334
  tree_hash=tree_hash,
335
+ key=key,
336
+ subject=subject,
337
337
  hotspots=hotspots,
338
338
  issues=issues,
339
339
  docstring_coverage=coverage,
@@ -472,6 +472,10 @@ class SnapshotManager(_BaseSnapshotManager):
472
472
  vs_previous=snapshot.__dict__["vs_previous"],
473
473
  vs_baseline=snapshot.__dict__["vs_baseline"],
474
474
  tree_hash=snapshot.tree_hash,
475
+ snapshot_key=snapshot.snapshot_key,
476
+ subject=snapshot.subject,
477
+ tool=snapshot.tool,
478
+ tool_version=snapshot.tool_version,
475
479
  )
476
480
  return super().save_snapshot(raw, force=force)
477
481
  return super().save_snapshot(snapshot, force=force)
File without changes