pycode-kg 0.19.1__tar.gz → 0.19.3__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.19.1 → pycode_kg-0.19.3}/PKG-INFO +7 -8
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/README.md +1 -1
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/pyproject.toml +21 -20
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/__init__.py +1 -1
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_build.py +11 -5
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_build_full.py +12 -6
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_init.py +1 -1
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_model.py +1 -1
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/graph.py +5 -3
- pycode_kg-0.19.3/src/pycode_kg/index.py +11 -0
- pycode_kg-0.19.3/src/pycode_kg/module/base.py +33 -0
- pycode_kg-0.19.3/src/pycode_kg/module/extractor.py +127 -0
- pycode_kg-0.19.3/src/pycode_kg/module/types.py +31 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/pycodekg.py +2 -1
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/snapshots.py +1 -1
- pycode_kg-0.19.3/src/pycode_kg/store.py +7 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/viz3d.py +40 -40
- pycode_kg-0.19.1/src/pycode_kg/index.py +0 -575
- pycode_kg-0.19.1/src/pycode_kg/module/base.py +0 -720
- pycode_kg-0.19.1/src/pycode_kg/module/extractor.py +0 -276
- pycode_kg-0.19.1/src/pycode_kg/module/types.py +0 -532
- pycode_kg-0.19.1/src/pycode_kg/store.py +0 -766
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/LICENSE +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/.DS_Store +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/__main__.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/analysis/__init__.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/analysis/bridge.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/analysis/centrality.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/analysis/framework_detector.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/analysis/hybrid_rank.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/app.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/architecture.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/build_pycodekg_lancedb.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/build_pycodekg_sqlite.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/__init__.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_analyze.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_architecture.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_bridges.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_centrality.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_explain.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_framework_nodes.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_hooks.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_mcp.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_query.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_snapshot.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/cmd_viz.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/main.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/cli/options.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/config.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/explain.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/kg.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/layout3d.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/mcp_server.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/module/__init__.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/pycodekg_query.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/pycodekg_snippet_packer.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/pycodekg_thorough_analysis.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/pycodekg_viz.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/pycodekg_viz3d.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/ranking/__init__.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/ranking/cli_rank.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/ranking/coderank.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/sql/004_add_centrality_table.sql +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/utils.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/src/pycode_kg/visitor.py +0 -0
- {pycode_kg-0.19.1 → pycode_kg-0.19.3}/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.19.
|
|
3
|
+
Version: 0.19.3
|
|
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
|
|
@@ -25,15 +25,12 @@ Requires-Dist: PyQt5 (>=5.15.0) ; extra == "viz3d"
|
|
|
25
25
|
Requires-Dist: click (>=8.1.0,<9)
|
|
26
26
|
Requires-Dist: detect-secrets (>=1.5.0) ; extra == "all"
|
|
27
27
|
Requires-Dist: detect-secrets (>=1.5.0) ; extra == "dev"
|
|
28
|
-
Requires-Dist: doc-kg (>=0.
|
|
29
|
-
Requires-Dist: doc-kg (>=0.
|
|
30
|
-
Requires-Dist: kgmodule-utils (>=0.
|
|
31
|
-
Requires-Dist: lancedb (>=0.29.0)
|
|
28
|
+
Requires-Dist: doc-kg (>=0.15.2) ; extra == "dev"
|
|
29
|
+
Requires-Dist: doc-kg (>=0.15.2) ; extra == "kgdeps"
|
|
30
|
+
Requires-Dist: kgmodule-utils[semantic] (>=0.3.1)
|
|
32
31
|
Requires-Dist: markdown (>=3.6) ; extra == "all"
|
|
33
32
|
Requires-Dist: markdown (>=3.6) ; extra == "viz3d"
|
|
34
33
|
Requires-Dist: mcp (>=1.0.0)
|
|
35
|
-
Requires-Dist: mypy (>=1.10.0) ; extra == "all"
|
|
36
|
-
Requires-Dist: mypy (>=1.10.0) ; extra == "dev"
|
|
37
34
|
Requires-Dist: numpy (>=1.24.0)
|
|
38
35
|
Requires-Dist: pandas (>=2.0.0)
|
|
39
36
|
Requires-Dist: param (>=2.0.0) ; extra == "all"
|
|
@@ -67,6 +64,8 @@ Requires-Dist: torch (>=2.5.1)
|
|
|
67
64
|
Requires-Dist: trame-vtk (>=2.0.0) ; extra == "all"
|
|
68
65
|
Requires-Dist: trame-vtk (>=2.0.0) ; extra == "viz3d"
|
|
69
66
|
Requires-Dist: transformers (>=4.40.0,<4.57)
|
|
67
|
+
Requires-Dist: ty (>=0.0.41) ; extra == "all"
|
|
68
|
+
Requires-Dist: ty (>=0.0.41) ; extra == "dev"
|
|
70
69
|
Project-URL: Homepage, https://github.com/Flux-Frontiers/pycode_kg
|
|
71
70
|
Project-URL: Repository, https://github.com/Flux-Frontiers/pycode_kg
|
|
72
71
|
Description-Content-Type: text/markdown
|
|
@@ -78,7 +77,7 @@ Description-Content-Type: text/markdown
|
|
|
78
77
|
|
|
79
78
|
[](https://www.python.org/)
|
|
80
79
|
[](https://www.elastic.co/licensing/elastic-license)
|
|
81
|
-
[](https://github.com/Flux-Frontiers/pycode_kg/releases)
|
|
82
81
|
[](https://github.com/Flux-Frontiers/pycode_kg/actions/workflows/ci.yml)
|
|
83
82
|
[](https://python-poetry.org/)
|
|
84
83
|
[](https://zenodo.org/badge/latestdoi/1202379010)
|
|
@@ -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)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
#
|
|
8
8
|
# Quick install (pip)
|
|
9
9
|
# -------------------
|
|
10
|
-
# pip install -e ".[dev]" core + dev tools (pytest, ruff,
|
|
10
|
+
# pip install -e ".[dev]" core + dev tools (pytest, ruff, ty, etc.)
|
|
11
11
|
# pip install -e ".[viz]" core + Streamlit/Plotly/PyVis visualizer
|
|
12
12
|
# pip install -e ".[viz3d]" core + PyVista 3D visualizer
|
|
13
13
|
# pip install -e ".[kgdeps]" core + KG integrations (doc-kg, agent-kg)
|
|
@@ -43,17 +43,12 @@
|
|
|
43
43
|
requires = ["poetry-core>=2.0.0"]
|
|
44
44
|
build-backend = "poetry.core.masonry.api"
|
|
45
45
|
|
|
46
|
-
[[tool.poetry.source]]
|
|
47
|
-
name = "testpypi"
|
|
48
|
-
url = "https://test.pypi.org/simple/"
|
|
49
|
-
priority = "supplemental"
|
|
50
|
-
|
|
51
46
|
[tool.poetry]
|
|
52
47
|
packages = [{ include = "pycode_kg", from = "src" }]
|
|
53
48
|
|
|
54
49
|
[tool.poetry.group.dev.dependencies]
|
|
55
50
|
detect-secrets = ">=1.5.0"
|
|
56
|
-
|
|
51
|
+
ty = "^0.0.41"
|
|
57
52
|
pdoc = ">=14.0.0"
|
|
58
53
|
pre-commit = ">=4.5.1"
|
|
59
54
|
pylint = ">=4.0.5"
|
|
@@ -66,7 +61,7 @@ ruff = ">=0.4.0"
|
|
|
66
61
|
# ---------------------------------------------------------------------------
|
|
67
62
|
[project]
|
|
68
63
|
name = "pycode-kg"
|
|
69
|
-
version = "0.19.
|
|
64
|
+
version = "0.19.3"
|
|
70
65
|
description = "A tool to build a searchable knowledge graph from Python repositories"
|
|
71
66
|
readme = "README.md"
|
|
72
67
|
license = "Elastic-2.0"
|
|
@@ -86,7 +81,6 @@ classifiers = [
|
|
|
86
81
|
requires-python = ">=3.12,<3.14"
|
|
87
82
|
dependencies = [
|
|
88
83
|
"click>=8.1.0,<9",
|
|
89
|
-
"lancedb>=0.29.0",
|
|
90
84
|
"mcp>=1.0.0",
|
|
91
85
|
"numpy>=1.24.0",
|
|
92
86
|
"pandas>=2.0.0",
|
|
@@ -95,20 +89,20 @@ dependencies = [
|
|
|
95
89
|
"sentence-transformers>=5.4.1",
|
|
96
90
|
"torch>=2.5.1",
|
|
97
91
|
"transformers>=4.40.0,<4.57",
|
|
98
|
-
"kgmodule-utils>=0.
|
|
92
|
+
"kgmodule-utils[semantic]>=0.3.1",
|
|
99
93
|
]
|
|
100
94
|
|
|
101
95
|
[project.optional-dependencies]
|
|
102
96
|
dev = [
|
|
103
97
|
"detect-secrets>=1.5.0",
|
|
104
|
-
"
|
|
98
|
+
"ty>=0.0.41",
|
|
105
99
|
"pdoc>=14.0.0",
|
|
106
100
|
"pre-commit>=4.5.1",
|
|
107
101
|
"pylint>=4.0.5",
|
|
108
102
|
"pytest>=8.0.0",
|
|
109
103
|
"pytest-cov>=5.0.0",
|
|
110
104
|
"ruff>=0.4.0",
|
|
111
|
-
"doc-kg>=0.
|
|
105
|
+
"doc-kg>=0.15.2",
|
|
112
106
|
# agent-kg not yet on PyPI — install manually: pip install git+https://github.com/Flux-Frontiers/agent_kg.git
|
|
113
107
|
]
|
|
114
108
|
viz = [
|
|
@@ -127,12 +121,11 @@ viz3d = [
|
|
|
127
121
|
|
|
128
122
|
# note that dockg is on pypi; agent-kg is not yet — install manually from git
|
|
129
123
|
kgdeps = [
|
|
130
|
-
"doc-kg>=0.
|
|
124
|
+
"doc-kg>=0.15.2",
|
|
131
125
|
]
|
|
132
126
|
all = [
|
|
133
127
|
"detect-secrets>=1.5.0",
|
|
134
128
|
"markdown>=3.6",
|
|
135
|
-
"mypy>=1.10.0",
|
|
136
129
|
"param>=2.0.0",
|
|
137
130
|
"pdoc>=14.0.0",
|
|
138
131
|
"plotly>=5.14.0",
|
|
@@ -147,6 +140,7 @@ all = [
|
|
|
147
140
|
"ruff>=0.4.0",
|
|
148
141
|
"streamlit>=1.35.0",
|
|
149
142
|
"trame-vtk>=2.0.0",
|
|
143
|
+
"ty>=0.0.41",
|
|
150
144
|
]
|
|
151
145
|
|
|
152
146
|
[project.urls]
|
|
@@ -183,12 +177,19 @@ target-version = "py312"
|
|
|
183
177
|
select = ["E", "F", "W", "I", "UP"]
|
|
184
178
|
ignore = ["E501"]
|
|
185
179
|
|
|
186
|
-
[tool.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
180
|
+
[tool.ty.environment]
|
|
181
|
+
python-version = "3.12"
|
|
182
|
+
root = ["src"]
|
|
183
|
+
|
|
184
|
+
[tool.ty.rules]
|
|
185
|
+
# Be lenient about third-party stubs (mirrors mypy's ignore_missing_imports).
|
|
186
|
+
unresolved-import = "ignore"
|
|
187
|
+
# viz3d.py carries `# ty: ignore` suppressions for param/PyQt5/pyvista false
|
|
188
|
+
# positives. Those libraries live in the optional viz/viz3d extras, so in the
|
|
189
|
+
# lean CI install the imports are Unknown, the errors don't fire, and the
|
|
190
|
+
# ignores look "unused". Don't fail the build on that — the suppressions are
|
|
191
|
+
# still honored locally where the extras (and the errors) are present.
|
|
192
|
+
unused-ignore-comment = "ignore"
|
|
192
193
|
|
|
193
194
|
[tool.pytest.ini_options]
|
|
194
195
|
testpaths = ["tests"]
|
|
@@ -32,7 +32,7 @@ KGModule SDK (build new domain KGs)::
|
|
|
32
32
|
from pycode_kg import KGModule, KGExtractor, PyCodeKGExtractor, NodeSpec, EdgeSpec
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
|
-
__version__ = "0.19.
|
|
35
|
+
__version__ = "0.19.3"
|
|
36
36
|
__author__ = "Eric G. Suchanek, PhD"
|
|
37
37
|
|
|
38
38
|
# Low-level primitives (locked v0 contract)
|
|
@@ -16,12 +16,12 @@ import click
|
|
|
16
16
|
from pycode_kg.cli.main import cli
|
|
17
17
|
from pycode_kg.cli.options import exclude_option, include_option, repo_option
|
|
18
18
|
from pycode_kg.config import load_exclude_dirs, load_include_dirs
|
|
19
|
-
from pycode_kg.graph import CodeGraph
|
|
20
19
|
from pycode_kg.index import (
|
|
21
20
|
SemanticIndex,
|
|
22
21
|
SentenceTransformerEmbedder,
|
|
23
22
|
suppress_ingestion_logging,
|
|
24
23
|
)
|
|
24
|
+
from pycode_kg.module.extractor import EdgeSpec, NodeSpec, PyCodeKGExtractor
|
|
25
25
|
from pycode_kg.pycodekg import DEFAULT_MODEL
|
|
26
26
|
from pycode_kg.store import GraphStore
|
|
27
27
|
|
|
@@ -53,19 +53,25 @@ def build_sqlite(
|
|
|
53
53
|
include = load_include_dirs(repo_root) | set(include_dir)
|
|
54
54
|
exclude = load_exclude_dirs(repo_root) | set(exclude_dir)
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
extractor = PyCodeKGExtractor(
|
|
57
57
|
repo_root,
|
|
58
58
|
include=include if include else None,
|
|
59
59
|
exclude=exclude if exclude else None,
|
|
60
60
|
)
|
|
61
|
-
|
|
61
|
+
node_specs: list[NodeSpec] = []
|
|
62
|
+
edge_specs: list[EdgeSpec] = []
|
|
63
|
+
for item in extractor.extract():
|
|
64
|
+
if isinstance(item, NodeSpec):
|
|
65
|
+
node_specs.append(item)
|
|
66
|
+
else:
|
|
67
|
+
edge_specs.append(item)
|
|
62
68
|
|
|
63
69
|
store = GraphStore(db_path)
|
|
64
|
-
store.write(
|
|
70
|
+
store.write(node_specs, edge_specs, wipe=wipe)
|
|
65
71
|
resolved = store.resolve_symbols()
|
|
66
72
|
store.close()
|
|
67
73
|
|
|
68
|
-
print(f"OK: nodes={len(
|
|
74
|
+
print(f"OK: nodes={len(node_specs)} edges={len(edge_specs)} resolved={resolved} db={db_path}")
|
|
69
75
|
|
|
70
76
|
|
|
71
77
|
@cli.command("build-lancedb")
|
|
@@ -22,12 +22,12 @@ from pycode_kg.cli.options import (
|
|
|
22
22
|
repo_option,
|
|
23
23
|
)
|
|
24
24
|
from pycode_kg.config import load_exclude_dirs, load_include_dirs
|
|
25
|
-
from pycode_kg.graph import CodeGraph
|
|
26
25
|
from pycode_kg.index import (
|
|
27
26
|
SemanticIndex,
|
|
28
27
|
SentenceTransformerEmbedder,
|
|
29
28
|
suppress_ingestion_logging,
|
|
30
29
|
)
|
|
30
|
+
from pycode_kg.module.extractor import EdgeSpec, NodeSpec, PyCodeKGExtractor
|
|
31
31
|
from pycode_kg.store import GraphStore
|
|
32
32
|
|
|
33
33
|
|
|
@@ -126,15 +126,21 @@ def _run_pipeline(
|
|
|
126
126
|
|
|
127
127
|
# Step 1: Build graph store
|
|
128
128
|
t1 = time.monotonic()
|
|
129
|
-
|
|
129
|
+
extractor = PyCodeKGExtractor(
|
|
130
130
|
repo_root,
|
|
131
131
|
include=include if include else None,
|
|
132
132
|
exclude=exclude if exclude else None,
|
|
133
133
|
)
|
|
134
|
-
|
|
134
|
+
node_specs: list[NodeSpec] = []
|
|
135
|
+
edge_specs: list[EdgeSpec] = []
|
|
136
|
+
for item in extractor.extract():
|
|
137
|
+
if isinstance(item, NodeSpec):
|
|
138
|
+
node_specs.append(item)
|
|
139
|
+
else:
|
|
140
|
+
edge_specs.append(item)
|
|
135
141
|
|
|
136
142
|
store = GraphStore(db_path)
|
|
137
|
-
store.write(
|
|
143
|
+
store.write(node_specs, edge_specs, wipe=wipe)
|
|
138
144
|
resolved = store.resolve_symbols()
|
|
139
145
|
store.close()
|
|
140
146
|
|
|
@@ -142,8 +148,8 @@ def _run_pipeline(
|
|
|
142
148
|
1,
|
|
143
149
|
"graph store",
|
|
144
150
|
[
|
|
145
|
-
("nodes", str(len(
|
|
146
|
-
("edges", str(len(
|
|
151
|
+
("nodes", str(len(node_specs))),
|
|
152
|
+
("edges", str(len(edge_specs))),
|
|
147
153
|
("resolved", str(resolved)),
|
|
148
154
|
],
|
|
149
155
|
elapsed=time.monotonic() - t1,
|
|
@@ -18,6 +18,7 @@ import tomllib
|
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
|
|
20
20
|
import click
|
|
21
|
+
from kg_utils.semantic import _local_model_path
|
|
21
22
|
|
|
22
23
|
from pycode_kg.cli.cmd_build_full import _run_pipeline
|
|
23
24
|
from pycode_kg.cli.cmd_hooks import _PRE_COMMIT_HOOK
|
|
@@ -28,7 +29,6 @@ from pycode_kg.cli.options import (
|
|
|
28
29
|
model_option,
|
|
29
30
|
repo_option,
|
|
30
31
|
)
|
|
31
|
-
from pycode_kg.index import _local_model_path
|
|
32
32
|
from pycode_kg.kg import PyCodeKG
|
|
33
33
|
from pycode_kg.pycodekg_thorough_analysis import PyCodeKGAnalyzer
|
|
34
34
|
from pycode_kg.snapshots import SnapshotManager
|
|
@@ -9,9 +9,9 @@ CLI command for managing the PyCodeKG embedding model cache.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import click
|
|
12
|
+
from kg_utils.semantic import _local_model_path
|
|
12
13
|
|
|
13
14
|
from pycode_kg.cli.main import cli
|
|
14
|
-
from pycode_kg.index import _local_model_path
|
|
15
15
|
from pycode_kg.pycodekg import DEFAULT_MODEL
|
|
16
16
|
|
|
17
17
|
|
|
@@ -78,14 +78,16 @@ class CodeGraph:
|
|
|
78
78
|
"""Extracted nodes (calls :meth:`extract` if needed)."""
|
|
79
79
|
if self._nodes is None:
|
|
80
80
|
self.extract()
|
|
81
|
-
|
|
81
|
+
assert self._nodes is not None
|
|
82
|
+
return self._nodes
|
|
82
83
|
|
|
83
84
|
@property
|
|
84
85
|
def edges(self) -> list[Edge]:
|
|
85
86
|
"""Extracted edges (calls :meth:`extract` if needed)."""
|
|
86
87
|
if self._edges is None:
|
|
87
88
|
self.extract()
|
|
88
|
-
|
|
89
|
+
assert self._edges is not None
|
|
90
|
+
return self._edges
|
|
89
91
|
|
|
90
92
|
def result(self) -> tuple[list[Node], list[Edge]]:
|
|
91
93
|
"""Return the extracted nodes and edges as a tuple.
|
|
@@ -120,6 +122,6 @@ class CodeGraph:
|
|
|
120
122
|
if extracted:
|
|
121
123
|
return (
|
|
122
124
|
f"CodeGraph(repo_root={self.repo_root!r}, "
|
|
123
|
-
f"nodes={len(self._nodes)}, edges={len(self._edges)})" #
|
|
125
|
+
f"nodes={len(self._nodes)}, edges={len(self._edges)})" # ty: ignore[invalid-argument-type]
|
|
124
126
|
)
|
|
125
127
|
return f"CodeGraph(repo_root={self.repo_root!r}, not yet extracted)"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""pycode_kg/index.py — Re-exports semantic index from kg_utils.semantic."""
|
|
2
|
+
|
|
3
|
+
from kg_utils.semantic import ( # noqa: F401
|
|
4
|
+
DEFAULT_MODEL,
|
|
5
|
+
Embedder,
|
|
6
|
+
SeedHit,
|
|
7
|
+
SemanticIndex,
|
|
8
|
+
SentenceTransformerEmbedder,
|
|
9
|
+
resolve_model_path,
|
|
10
|
+
suppress_ingestion_logging,
|
|
11
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""pycode_kg/module/base.py — KGModule for pycode_kg: thin subclass of kg_utils.pipeline."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import abstractmethod
|
|
6
|
+
|
|
7
|
+
from kg_utils.extractor import KGExtractor
|
|
8
|
+
from kg_utils.pipeline import KGModule as _KGModuleBase
|
|
9
|
+
from kg_utils.store import GraphStore
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class KGModule(_KGModuleBase):
|
|
13
|
+
"""Abstract base for Python code knowledge graphs.
|
|
14
|
+
|
|
15
|
+
Domain authors implement :meth:`make_extractor`, :meth:`kind`, and
|
|
16
|
+
:meth:`analyze`. Build/query/pack infrastructure comes from
|
|
17
|
+
:class:`kg_utils.pipeline.KGModule`.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
_default_dir: str = ".pycodekg"
|
|
21
|
+
|
|
22
|
+
def _post_build_hook(self, store: GraphStore) -> None:
|
|
23
|
+
"""Run symbol resolution after the graph is written."""
|
|
24
|
+
store.resolve_symbols()
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def make_extractor(self) -> KGExtractor: ...
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def kind(self) -> str: ...
|
|
31
|
+
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def analyze(self) -> str: ...
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
module/extractor.py
|
|
4
|
+
|
|
5
|
+
KGExtractor — abstract extraction protocol for any knowledge graph domain.
|
|
6
|
+
|
|
7
|
+
NodeSpec and EdgeSpec are imported from kg_utils.specs and re-exported here.
|
|
8
|
+
PyCodeKGExtractor is the Python-AST-backed implementation.
|
|
9
|
+
|
|
10
|
+
Author: Eric G. Suchanek, PhD
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from collections.abc import Iterator
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from kg_utils.extractor import KGExtractor # noqa: F401
|
|
20
|
+
from kg_utils.specs import EdgeSpec, NodeSpec # noqa: F401
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# PyCodeKGExtractor — Python-AST-backed extractor
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PyCodeKGExtractor(KGExtractor):
|
|
28
|
+
"""KGExtractor backed by CodeGraph (Python AST analysis).
|
|
29
|
+
|
|
30
|
+
Wraps :class:`~pycode_kg.graph.CodeGraph` and converts its :class:`Node`
|
|
31
|
+
and :class:`Edge` v0 primitives to :class:`NodeSpec` / :class:`EdgeSpec`
|
|
32
|
+
for the generic :class:`~pycode_kg.module.base.KGModule` build pipeline.
|
|
33
|
+
|
|
34
|
+
This is the extractor used by :class:`~pycode_kg.kg.PyCodeKG` and is the
|
|
35
|
+
reference implementation for source-code KG extractors.
|
|
36
|
+
|
|
37
|
+
:param repo_path: Path to the Python repository root.
|
|
38
|
+
:param include: Set of top-level directory names to include (all if empty).
|
|
39
|
+
:param exclude: Set of directory names to exclude at every depth.
|
|
40
|
+
:param config: Optional config dict (forwarded to super).
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
repo_path: Path,
|
|
46
|
+
*,
|
|
47
|
+
include: set[str] | None = None,
|
|
48
|
+
exclude: set[str] | None = None,
|
|
49
|
+
config: dict[str, Any] | None = None,
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Initialise the extractor for a Python repository.
|
|
52
|
+
|
|
53
|
+
:param repo_path: Path to the Python repository root.
|
|
54
|
+
:param include: Top-level directory names to include (empty = all).
|
|
55
|
+
:param exclude: Directory names to exclude at every walk depth.
|
|
56
|
+
:param config: Optional domain-specific configuration dict.
|
|
57
|
+
"""
|
|
58
|
+
super().__init__(repo_path, config)
|
|
59
|
+
self._include: set[str] = include or set()
|
|
60
|
+
self._exclude: set[str] = exclude or set()
|
|
61
|
+
|
|
62
|
+
def node_kinds(self) -> list[str]:
|
|
63
|
+
"""Return the Python AST node kinds.
|
|
64
|
+
|
|
65
|
+
:return: ``['module', 'class', 'function', 'method', 'symbol']``
|
|
66
|
+
"""
|
|
67
|
+
return ["module", "class", "function", "method", "symbol"]
|
|
68
|
+
|
|
69
|
+
def edge_kinds(self) -> list[str]:
|
|
70
|
+
"""Return the Python AST edge relation types.
|
|
71
|
+
|
|
72
|
+
:return: List of all relation strings emitted by the Python extractor.
|
|
73
|
+
"""
|
|
74
|
+
return [
|
|
75
|
+
"CONTAINS",
|
|
76
|
+
"CALLS",
|
|
77
|
+
"IMPORTS",
|
|
78
|
+
"INHERITS",
|
|
79
|
+
"READS",
|
|
80
|
+
"WRITES",
|
|
81
|
+
"ATTR_ACCESS",
|
|
82
|
+
"DEPENDS_ON",
|
|
83
|
+
"RESOLVES_TO",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
def meaningful_node_kinds(self) -> list[str]:
|
|
87
|
+
"""Return the node kinds indexed by LanceDB and counted in coverage.
|
|
88
|
+
|
|
89
|
+
Excludes ``'symbol'`` (unresolved import stubs).
|
|
90
|
+
|
|
91
|
+
:return: ``['module', 'class', 'function', 'method']``
|
|
92
|
+
"""
|
|
93
|
+
return ["module", "class", "function", "method"]
|
|
94
|
+
|
|
95
|
+
def extract(self) -> Iterator[NodeSpec | EdgeSpec]:
|
|
96
|
+
"""Run Python AST extraction and yield NodeSpec / EdgeSpec objects.
|
|
97
|
+
|
|
98
|
+
Delegates to :class:`~pycode_kg.graph.CodeGraph` for the AST walk, then
|
|
99
|
+
converts the v0-locked :class:`~pycode_kg.pycodekg.Node` and
|
|
100
|
+
:class:`~pycode_kg.pycodekg.Edge` primitives to the generic spec types.
|
|
101
|
+
|
|
102
|
+
:return: Iterator of :class:`NodeSpec` and :class:`EdgeSpec` objects.
|
|
103
|
+
"""
|
|
104
|
+
from pycode_kg.graph import CodeGraph # pylint: disable=import-outside-toplevel
|
|
105
|
+
|
|
106
|
+
graph = CodeGraph(self.repo_path, include=self._include, exclude=self._exclude)
|
|
107
|
+
nodes, edges = graph.result()
|
|
108
|
+
|
|
109
|
+
for n in nodes:
|
|
110
|
+
yield NodeSpec(
|
|
111
|
+
node_id=n.id,
|
|
112
|
+
kind=n.kind,
|
|
113
|
+
name=n.name,
|
|
114
|
+
qualname=n.qualname or "",
|
|
115
|
+
source_path=n.module_path or "",
|
|
116
|
+
lineno=n.lineno,
|
|
117
|
+
end_lineno=n.end_lineno,
|
|
118
|
+
docstring=n.docstring or "",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
for e in edges:
|
|
122
|
+
yield EdgeSpec(
|
|
123
|
+
source_id=e.src,
|
|
124
|
+
target_id=e.dst,
|
|
125
|
+
relation=e.rel,
|
|
126
|
+
metadata={"evidence": e.evidence} if e.evidence else {},
|
|
127
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""pycode_kg/module/types.py — Re-exports from kg_utils for backward compat."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from kg_utils.pipeline import ( # noqa: F401
|
|
6
|
+
compute_span,
|
|
7
|
+
docstring_signal,
|
|
8
|
+
lexical_overlap_score,
|
|
9
|
+
make_module_summary,
|
|
10
|
+
make_snippet,
|
|
11
|
+
normalize_query_text,
|
|
12
|
+
query_tokens,
|
|
13
|
+
read_lines,
|
|
14
|
+
safe_join,
|
|
15
|
+
semantic_score_from_distance,
|
|
16
|
+
spans_overlap,
|
|
17
|
+
)
|
|
18
|
+
from kg_utils.specs import BuildStats, QueryResult, SnippetPack # noqa: F401
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class Snippet:
|
|
23
|
+
"""Backward-compat shim. Snippets are now dicts on node["snippet"]."""
|
|
24
|
+
|
|
25
|
+
path: str
|
|
26
|
+
start: int
|
|
27
|
+
end: int
|
|
28
|
+
text: str
|
|
29
|
+
|
|
30
|
+
def to_dict(self) -> dict:
|
|
31
|
+
return {"path": self.path, "start": self.start, "end": self.end, "text": self.text}
|
|
@@ -37,7 +37,8 @@ from pathlib import Path
|
|
|
37
37
|
# ============================================================================
|
|
38
38
|
# Configuration
|
|
39
39
|
# ============================================================================
|
|
40
|
-
from
|
|
40
|
+
from kg_utils.semantic import DEFAULT_MODEL as DEFAULT_MODEL # noqa: F401 — re-exported
|
|
41
|
+
|
|
41
42
|
from pycode_kg.utils import node_id, rel_module_path
|
|
42
43
|
from pycode_kg.visitor import PyCodeKGVisitor
|
|
43
44
|
|
|
@@ -284,7 +284,7 @@ class SnapshotManager(_BaseSnapshotManager):
|
|
|
284
284
|
# capture — backwards-compat wrapper
|
|
285
285
|
# ------------------------------------------------------------------
|
|
286
286
|
|
|
287
|
-
def capture( #
|
|
287
|
+
def capture( # ty: ignore[invalid-method-override]
|
|
288
288
|
self,
|
|
289
289
|
version: str | None = None,
|
|
290
290
|
branch: str | None = None,
|