modwire 2.0.0__tar.gz → 2.1.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.
- {modwire-2.0.0 → modwire-2.1.0}/PKG-INFO +1 -1
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/__init__.py +10 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/_version.py +3 -3
- modwire-2.1.0/src/modwire/callables.py +162 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/definitions.py +64 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extraction/models.py +49 -1
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extraction/serialization.py +3 -2
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/base.py +3 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/scripts/php_extractor.php +459 -5
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/scripts/python_extractor.py +393 -2
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/scripts/typescript_extractor.js +380 -2
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/testing/factories.py +109 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire.egg-info/PKG-INFO +1 -1
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire.egg-info/SOURCES.txt +1 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/test_api.py +211 -1
- {modwire-2.0.0 → modwire-2.1.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/.github/workflows/ci.yml +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/.github/workflows/release.yml +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/.gitignore +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/CONTRIBUTING.md +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/LICENSE +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/README.md +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/docs/wiki/Development-checks.md +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/docs/wiki/Home.md +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/docs/wiki/Reporting-bugs.md +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/docs/wiki/Requesting-features.md +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/pyproject.toml +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/setup.cfg +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/show_test_source_files.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/architecture/__init__.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/architecture/analyzers.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/architecture/config.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/architecture/insights.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/architecture/matching.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/architecture/policy.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/architecture/render.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/architecture/violations.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/exports.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extraction/__init__.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extraction/cache.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extraction/manifest.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extraction/roots.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extraction/service.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/__init__.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/loader.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/php.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/python.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/extractors/typescript.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/graph.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/metadata.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/shape/__init__.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/shape/config.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/shape/evaluator.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/shape/rules.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/shape/violations.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire/testing/__init__.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire.egg-info/dependency_links.txt +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire.egg-info/requires.txt +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/src/modwire.egg-info/top_level.txt +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/php/ignored/generated.php +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/php/src/application/use_cases/activate.php +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/php/src/domain/model/user.php +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/php/src/domain/services/policy.php +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/php/src/interfaces/http/controller.php +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/python/ignored/generated.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/python/src/application/use_cases/activate.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/python/src/domain/model/user.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/python/src/domain/services/policy.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/python/src/interfaces/http/controller.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/typescript/ignored/generated.ts +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/typescript/src/application/use_cases/activate.ts +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/typescript/src/domain/model/profile.tsx +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/typescript/src/domain/model/user.ts +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/typescript/src/domain/services/audit.js +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/typescript/src/domain/services/policy.ts +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/typescript/src/interfaces/http/controller.ts +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/apps/typescript/src/interfaces/http/view.jsx +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/test_architecture_api.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/tests/test_standalone.py +0 -0
- {modwire-2.0.0 → modwire-2.1.0}/uv.lock +0 -0
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
from ._version import __version__
|
|
2
|
+
from .callables import (
|
|
3
|
+
CallableReportEntry,
|
|
4
|
+
callable_report_entries,
|
|
5
|
+
render_callable_report,
|
|
6
|
+
structured_callable_report,
|
|
7
|
+
)
|
|
2
8
|
from .extraction import (
|
|
3
9
|
CodeMap,
|
|
4
10
|
CodeMapSerializationError,
|
|
@@ -46,6 +52,7 @@ from .shape import (
|
|
|
46
52
|
__all__ = [
|
|
47
53
|
"CodeMap",
|
|
48
54
|
"CodeMapSerializationError",
|
|
55
|
+
"CallableReportEntry",
|
|
49
56
|
"DependencyGraph",
|
|
50
57
|
"Edge",
|
|
51
58
|
"EXTRACTION_SCHEMA_VERSION",
|
|
@@ -69,6 +76,7 @@ __all__ = [
|
|
|
69
76
|
"UnusedExport",
|
|
70
77
|
"__version__",
|
|
71
78
|
"build_dependency_graph",
|
|
79
|
+
"callable_report_entries",
|
|
72
80
|
"deserialize_code_map",
|
|
73
81
|
"discover_sources",
|
|
74
82
|
"evaluate_shape",
|
|
@@ -79,8 +87,10 @@ __all__ = [
|
|
|
79
87
|
"languages",
|
|
80
88
|
"normalize_source_id",
|
|
81
89
|
"require_runtime",
|
|
90
|
+
"render_callable_report",
|
|
82
91
|
"runtime_diagnostics",
|
|
83
92
|
"serialize_code_map",
|
|
93
|
+
"structured_callable_report",
|
|
84
94
|
"supported_languages",
|
|
85
95
|
"validate_shape_config",
|
|
86
96
|
]
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.
|
|
22
|
-
__version_tuple__ = version_tuple = (2,
|
|
21
|
+
__version__ = version = '2.1.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 1, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g54f33f5a3'
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Callable
|
|
5
|
+
|
|
6
|
+
from .definitions import SourceCall, SourceCallable
|
|
7
|
+
from .extraction import CodeMap
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
PathDisplay = Callable[[str], str]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class CallableReportEntry:
|
|
15
|
+
source_callable: SourceCallable
|
|
16
|
+
calls: tuple[SourceCall, ...]
|
|
17
|
+
callers: tuple[SourceCall, ...]
|
|
18
|
+
|
|
19
|
+
def to_dict(self) -> dict[str, object]:
|
|
20
|
+
return {
|
|
21
|
+
"callable": self.source_callable.model_dump(mode="json"),
|
|
22
|
+
"calls": [source_call.model_dump(mode="json") for source_call in self.calls],
|
|
23
|
+
"callers": [
|
|
24
|
+
source_call.model_dump(mode="json") for source_call in self.callers
|
|
25
|
+
],
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def callable_report_entries(code_map: CodeMap) -> tuple[CallableReportEntry, ...]:
|
|
30
|
+
return tuple(
|
|
31
|
+
CallableReportEntry(
|
|
32
|
+
source_callable=source_callable,
|
|
33
|
+
calls=tuple(
|
|
34
|
+
sorted(
|
|
35
|
+
code_map.calls_from(source_callable.id),
|
|
36
|
+
key=lambda source_call: (
|
|
37
|
+
source_call.line,
|
|
38
|
+
source_call.target_name,
|
|
39
|
+
source_call.expression,
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
),
|
|
43
|
+
callers=tuple(
|
|
44
|
+
sorted(
|
|
45
|
+
code_map.calls_to(source_callable.id),
|
|
46
|
+
key=lambda source_call: (
|
|
47
|
+
source_call.source_id,
|
|
48
|
+
source_call.line,
|
|
49
|
+
source_call.source_callable_id,
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
for source_callable in sorted(
|
|
55
|
+
(
|
|
56
|
+
source_callable
|
|
57
|
+
for source_file in code_map.extraction_result.files.values()
|
|
58
|
+
for source_callable in source_file.callables
|
|
59
|
+
),
|
|
60
|
+
key=lambda source_callable: (
|
|
61
|
+
source_callable.source_id,
|
|
62
|
+
source_callable.line_start,
|
|
63
|
+
source_callable.qualified_name,
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def structured_callable_report(code_map: CodeMap) -> tuple[dict[str, object], ...]:
|
|
70
|
+
return tuple(entry.to_dict() for entry in callable_report_entries(code_map))
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def render_callable_report(
|
|
74
|
+
code_map: CodeMap,
|
|
75
|
+
*,
|
|
76
|
+
path_display: PathDisplay = str,
|
|
77
|
+
) -> str:
|
|
78
|
+
entries = callable_report_entries(code_map)
|
|
79
|
+
if not entries:
|
|
80
|
+
return "Callable Report\n\nNo callables found."
|
|
81
|
+
|
|
82
|
+
callable_names = {
|
|
83
|
+
entry.source_callable.id: entry.source_callable.qualified_name
|
|
84
|
+
for entry in entries
|
|
85
|
+
}
|
|
86
|
+
lines = ["Callable Report", ""]
|
|
87
|
+
current_source_id = ""
|
|
88
|
+
for entry in entries:
|
|
89
|
+
source_callable = entry.source_callable
|
|
90
|
+
if source_callable.source_id != current_source_id:
|
|
91
|
+
current_source_id = source_callable.source_id
|
|
92
|
+
lines.extend([f"## {path_display(current_source_id)}", ""])
|
|
93
|
+
lines.append(
|
|
94
|
+
"- "
|
|
95
|
+
f"{source_callable.qualified_name} "
|
|
96
|
+
f"[{source_callable.kind}] "
|
|
97
|
+
f"lines {source_callable.line_start}-{source_callable.line_end}"
|
|
98
|
+
)
|
|
99
|
+
lines.append(" Calls:")
|
|
100
|
+
lines.extend(
|
|
101
|
+
_call_lines(
|
|
102
|
+
entry.calls,
|
|
103
|
+
callable_names=callable_names,
|
|
104
|
+
direction="outgoing",
|
|
105
|
+
path_display=path_display,
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
lines.append(" Called by:")
|
|
109
|
+
lines.extend(
|
|
110
|
+
_call_lines(
|
|
111
|
+
entry.callers,
|
|
112
|
+
callable_names=callable_names,
|
|
113
|
+
direction="incoming",
|
|
114
|
+
path_display=path_display,
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
lines.append("")
|
|
118
|
+
return "\n".join(lines).rstrip()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _call_lines(
|
|
122
|
+
calls: tuple[SourceCall, ...],
|
|
123
|
+
*,
|
|
124
|
+
callable_names: dict[str, str],
|
|
125
|
+
direction: str,
|
|
126
|
+
path_display: PathDisplay,
|
|
127
|
+
) -> list[str]:
|
|
128
|
+
if not calls:
|
|
129
|
+
return [" - none"]
|
|
130
|
+
|
|
131
|
+
rendered = []
|
|
132
|
+
for source_call in calls:
|
|
133
|
+
if direction == "incoming":
|
|
134
|
+
caller_name = callable_names.get(
|
|
135
|
+
source_call.source_callable_id,
|
|
136
|
+
source_call.source_callable_id,
|
|
137
|
+
)
|
|
138
|
+
rendered.append(
|
|
139
|
+
f" - {caller_name} "
|
|
140
|
+
f"at {path_display(source_call.source_id)}:{source_call.line}"
|
|
141
|
+
)
|
|
142
|
+
continue
|
|
143
|
+
|
|
144
|
+
target = (
|
|
145
|
+
callable_names[source_call.target_callable_id]
|
|
146
|
+
if source_call.target_callable_id in callable_names
|
|
147
|
+
else source_call.target_name
|
|
148
|
+
)
|
|
149
|
+
rendered.append(
|
|
150
|
+
f" - {source_call.expression} -> {target} "
|
|
151
|
+
f"at {path_display(source_call.source_id)}:{source_call.line} "
|
|
152
|
+
f"({source_call.resolution})"
|
|
153
|
+
)
|
|
154
|
+
return rendered
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
__all__ = [
|
|
158
|
+
"CallableReportEntry",
|
|
159
|
+
"callable_report_entries",
|
|
160
|
+
"render_callable_report",
|
|
161
|
+
"structured_callable_report",
|
|
162
|
+
]
|
|
@@ -6,6 +6,19 @@ from pydantic import BaseModel, Field
|
|
|
6
6
|
ImportCrossingType = Literal["module", "symbol"]
|
|
7
7
|
SourceVisibility = Literal["public", "protected", "private"]
|
|
8
8
|
SourceSignatureKind = Literal["call", "construct", "index"]
|
|
9
|
+
SourceValueDeclarationKind = Literal["assignment", "constant", "property", "unknown"]
|
|
10
|
+
SourceValueKind = Literal["callable", "class", "literal", "object", "unknown"]
|
|
11
|
+
SourceParameterKind = Literal["positional", "vararg", "keyword_only", "kwarg"]
|
|
12
|
+
SourceCallableKind = Literal[
|
|
13
|
+
"function",
|
|
14
|
+
"method",
|
|
15
|
+
"classmethod",
|
|
16
|
+
"staticmethod",
|
|
17
|
+
"constructor",
|
|
18
|
+
"callable_value",
|
|
19
|
+
"anonymous",
|
|
20
|
+
]
|
|
21
|
+
SourceCallResolution = Literal["resolved", "unresolved", "external", "dynamic"]
|
|
9
22
|
SourceExportKind = Literal[
|
|
10
23
|
"module",
|
|
11
24
|
"class",
|
|
@@ -64,6 +77,54 @@ class SourceFunction(BaseModel):
|
|
|
64
77
|
optional_args: int
|
|
65
78
|
|
|
66
79
|
|
|
80
|
+
class SourceValue(BaseModel):
|
|
81
|
+
name: str
|
|
82
|
+
visibility: SourceVisibility
|
|
83
|
+
visibility_intent: SourceVisibility
|
|
84
|
+
line_count: int
|
|
85
|
+
declaration_kind: SourceValueDeclarationKind
|
|
86
|
+
value_kind: SourceValueKind
|
|
87
|
+
declared_args: int = 0
|
|
88
|
+
optional_args: int = 0
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class SourceParameter(BaseModel):
|
|
92
|
+
name: str
|
|
93
|
+
annotation: str = ""
|
|
94
|
+
kind: SourceParameterKind
|
|
95
|
+
has_default: bool = False
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class SourceCallable(BaseModel):
|
|
99
|
+
id: str
|
|
100
|
+
source_id: str
|
|
101
|
+
name: str
|
|
102
|
+
qualified_name: str
|
|
103
|
+
owner_name: str = ""
|
|
104
|
+
kind: SourceCallableKind
|
|
105
|
+
visibility: SourceVisibility
|
|
106
|
+
visibility_intent: SourceVisibility
|
|
107
|
+
line_start: int
|
|
108
|
+
line_end: int
|
|
109
|
+
line_count: int
|
|
110
|
+
parameters: list[SourceParameter] = Field(default_factory=list)
|
|
111
|
+
declared_args: int = 0
|
|
112
|
+
optional_args: int = 0
|
|
113
|
+
return_annotation: str = ""
|
|
114
|
+
decorators: list[str] = Field(default_factory=list)
|
|
115
|
+
docstring: str = ""
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class SourceCall(BaseModel):
|
|
119
|
+
source_callable_id: str
|
|
120
|
+
target_callable_id: str = ""
|
|
121
|
+
source_id: str
|
|
122
|
+
line: int
|
|
123
|
+
expression: str
|
|
124
|
+
resolution: SourceCallResolution
|
|
125
|
+
target_name: str
|
|
126
|
+
|
|
127
|
+
|
|
67
128
|
class SourceClassMethod(BaseModel):
|
|
68
129
|
name: str
|
|
69
130
|
visibility: SourceVisibility
|
|
@@ -131,6 +192,9 @@ class SourceFile(BaseModel):
|
|
|
131
192
|
types: list[SourceType] = Field(default_factory=list)
|
|
132
193
|
abstract_classes: list[SourceAbstractClass] = Field(default_factory=list)
|
|
133
194
|
functions: list[SourceFunction]
|
|
195
|
+
values: list[SourceValue] = Field(default_factory=list)
|
|
196
|
+
callables: list[SourceCallable] = Field(default_factory=list)
|
|
197
|
+
calls: list[SourceCall] = Field(default_factory=list)
|
|
134
198
|
line_count: int
|
|
135
199
|
code_line_count: int
|
|
136
200
|
public_symbol_count: int
|
|
@@ -5,7 +5,7 @@ from dataclasses import dataclass
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
from ..definitions import SourceFile
|
|
8
|
+
from ..definitions import SourceCall, SourceCallable, SourceFile
|
|
9
9
|
from ..graph import DependencyGraph, Edge
|
|
10
10
|
from .roots import SourceIdMode
|
|
11
11
|
|
|
@@ -58,6 +58,54 @@ class CodeMap:
|
|
|
58
58
|
def external_edges(self) -> tuple[Edge, ...]:
|
|
59
59
|
return self.graph.external_edges(self.source_ids())
|
|
60
60
|
|
|
61
|
+
def callable_ids(self) -> tuple[str, ...]:
|
|
62
|
+
return tuple(
|
|
63
|
+
source_callable.id
|
|
64
|
+
for source_file in self.extraction_result.files.values()
|
|
65
|
+
for source_callable in source_file.callables
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def callable(self, callable_id: str) -> SourceCallable:
|
|
69
|
+
for source_file in self.extraction_result.files.values():
|
|
70
|
+
for source_callable in source_file.callables:
|
|
71
|
+
if source_callable.id == callable_id:
|
|
72
|
+
return source_callable
|
|
73
|
+
raise KeyError(callable_id)
|
|
74
|
+
|
|
75
|
+
def calls_from(self, callable_id: str) -> tuple[SourceCall, ...]:
|
|
76
|
+
return tuple(
|
|
77
|
+
source_call
|
|
78
|
+
for source_file in self.extraction_result.files.values()
|
|
79
|
+
for source_call in source_file.calls
|
|
80
|
+
if source_call.source_callable_id == callable_id
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def calls_to(self, callable_id: str) -> tuple[SourceCall, ...]:
|
|
84
|
+
return tuple(
|
|
85
|
+
source_call
|
|
86
|
+
for source_file in self.extraction_result.files.values()
|
|
87
|
+
for source_call in source_file.calls
|
|
88
|
+
if source_call.target_callable_id == callable_id
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def callable_graph(self) -> DependencyGraph:
|
|
92
|
+
graph = DependencyGraph()
|
|
93
|
+
callable_ids = set(self.callable_ids())
|
|
94
|
+
for callable_id in sorted(callable_ids):
|
|
95
|
+
graph.add_node(callable_id, kind="callable")
|
|
96
|
+
for source_file in self.extraction_result.files.values():
|
|
97
|
+
for source_call in source_file.calls:
|
|
98
|
+
if (
|
|
99
|
+
source_call.source_callable_id in callable_ids
|
|
100
|
+
and source_call.target_callable_id in callable_ids
|
|
101
|
+
):
|
|
102
|
+
graph.add_edge(
|
|
103
|
+
source_call.source_callable_id,
|
|
104
|
+
source_call.target_callable_id,
|
|
105
|
+
kind="call",
|
|
106
|
+
)
|
|
107
|
+
return graph
|
|
108
|
+
|
|
61
109
|
def tracked_only(self) -> CodeMap:
|
|
62
110
|
return self.subgraph(self.source_ids())
|
|
63
111
|
|
|
@@ -7,7 +7,8 @@ from ..graph import DependencyGraph, Edge, Node
|
|
|
7
7
|
from .models import CodeMap, ExtractionResult, ExtractionSummary
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
CODE_MAP_SCHEMA_VERSION =
|
|
10
|
+
CODE_MAP_SCHEMA_VERSION = 2
|
|
11
|
+
SUPPORTED_CODE_MAP_SCHEMA_VERSIONS = {1, CODE_MAP_SCHEMA_VERSION}
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class CodeMapSerializationError(ValueError):
|
|
@@ -55,7 +56,7 @@ def deserialize_code_map(
|
|
|
55
56
|
cache_key: str = "",
|
|
56
57
|
) -> CodeMap:
|
|
57
58
|
try:
|
|
58
|
-
if payload["schema_version"]
|
|
59
|
+
if payload["schema_version"] not in SUPPORTED_CODE_MAP_SCHEMA_VERSIONS:
|
|
59
60
|
raise CodeMapSerializationError(
|
|
60
61
|
f"Unsupported CodeMap schema version: {payload['schema_version']}"
|
|
61
62
|
)
|
|
@@ -151,6 +151,9 @@ class SourceExtractor(Protocol):
|
|
|
151
151
|
types=source_file.types,
|
|
152
152
|
abstract_classes=source_file.abstract_classes,
|
|
153
153
|
functions=source_file.functions,
|
|
154
|
+
values=source_file.values,
|
|
155
|
+
callables=source_file.callables,
|
|
156
|
+
calls=source_file.calls,
|
|
154
157
|
line_count=source_file.line_count,
|
|
155
158
|
code_line_count=source_file.code_line_count,
|
|
156
159
|
public_symbol_count=source_file.public_symbol_count,
|