cartograph-python 0.2.0__cp38-abi3-win_amd64.whl

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.
cartograph/aio.py ADDED
@@ -0,0 +1,238 @@
1
+ """Asynchronous CodeGraph engine interface using asyncio and thread offloading."""
2
+ from __future__ import annotations
3
+
4
+ import asyncio
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING, Any, Literal
7
+
8
+ from cartograph.codegraph import CodeGraph
9
+ from cartograph.models import (
10
+ ComplexityReport,
11
+ DeadCodeReport,
12
+ DiagnosisReport,
13
+ DiagramResult,
14
+ GraphStats,
15
+ ImpactResult,
16
+ IndexStats,
17
+ LintArchReport,
18
+ LocateResult,
19
+ LogicReport,
20
+ RouteTrace,
21
+ TestSelectorResult,
22
+ )
23
+
24
+ if TYPE_CHECKING:
25
+ import igraph as ig
26
+ import networkx as nx
27
+ import pandas as pd
28
+ import polars as pl
29
+
30
+
31
+ class AsyncCodeGraph:
32
+ """Asynchronous CodeGraph engine interface for async services, agents, and FastAPI."""
33
+
34
+ def __init__(
35
+ self,
36
+ path: str | Path | None = None,
37
+ profile: str = "default",
38
+ in_memory: bool = False,
39
+ ) -> None:
40
+ self._sync_graph = CodeGraph(path=path, profile=profile, in_memory=in_memory)
41
+
42
+ @classmethod
43
+ async def open(
44
+ cls,
45
+ path: str | Path | None = None,
46
+ profile: str = "default",
47
+ in_memory: bool = False,
48
+ ) -> AsyncCodeGraph:
49
+ """Asynchronously open or initialize an AsyncCodeGraph instance."""
50
+ return await asyncio.to_thread(cls, path=path, profile=profile, in_memory=in_memory)
51
+
52
+ async def __aenter__(self) -> AsyncCodeGraph:
53
+ return self
54
+
55
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
56
+ await self.close()
57
+
58
+ async def close(self) -> None:
59
+ """Asynchronously close database connections and release resources."""
60
+ await asyncio.to_thread(self._sync_graph.close)
61
+
62
+ @property
63
+ def is_open(self) -> bool:
64
+ """Check if database connection is active."""
65
+ return self._sync_graph.is_open
66
+
67
+ @property
68
+ def profile(self) -> str:
69
+ """Active storage profile name."""
70
+ return self._sync_graph.profile
71
+
72
+ async def index(
73
+ self,
74
+ force: bool = False,
75
+ staged: bool = False,
76
+ branch: str | None = None,
77
+ threads: int | None = None,
78
+ ) -> IndexStats:
79
+ """Scan workspace and populate the knowledge graph asynchronously."""
80
+ return await asyncio.to_thread(
81
+ self._sync_graph.index, force=force, staged=staged, branch=branch, threads=threads
82
+ )
83
+
84
+ async def status(self) -> GraphStats:
85
+ """Return aggregate statistics and health of the graph store asynchronously."""
86
+ return await asyncio.to_thread(self._sync_graph.status)
87
+
88
+ async def locate(
89
+ self,
90
+ query: str,
91
+ code: bool = False,
92
+ limit: int = 10,
93
+ ) -> LocateResult:
94
+ """Natural language or exact code subgraph localization asynchronously."""
95
+ return await asyncio.to_thread(
96
+ self._sync_graph.locate, query=query, code=code, limit=limit
97
+ )
98
+
99
+ async def impact(
100
+ self,
101
+ target: str,
102
+ branch: str | None = None,
103
+ staged: bool = False,
104
+ depth: int = 3,
105
+ ) -> ImpactResult:
106
+ """Perform topological blast-radius and risk analysis asynchronously."""
107
+ return await asyncio.to_thread(
108
+ self._sync_graph.impact, target=target, branch=branch, staged=staged, depth=depth
109
+ )
110
+
111
+ async def test_selector(
112
+ self,
113
+ target: str,
114
+ branch: str | None = None,
115
+ ) -> TestSelectorResult:
116
+ """Predict minimal test set exercising the changed target asynchronously."""
117
+ return await asyncio.to_thread(
118
+ self._sync_graph.test_selector, target=target, branch=branch
119
+ )
120
+
121
+ async def routes(
122
+ self,
123
+ filter_query: str | None = None,
124
+ ) -> list[RouteTrace]:
125
+ """Discover API routes, controller endpoints, and full-stack traces asynchronously."""
126
+ return await asyncio.to_thread(
127
+ self._sync_graph.routes, filter_query=filter_query
128
+ )
129
+
130
+ async def lint_arch(
131
+ self,
132
+ strict: bool = False,
133
+ ) -> LintArchReport:
134
+ """Detect architecture boundary violations and circular dependencies asynchronously."""
135
+ return await asyncio.to_thread(
136
+ self._sync_graph.lint_arch, strict=strict
137
+ )
138
+
139
+ async def complexity(
140
+ self,
141
+ top: int = 15,
142
+ danger_zone: bool = False,
143
+ ) -> ComplexityReport:
144
+ """Analyze cyclomatic/cognitive complexity and test deficits asynchronously."""
145
+ return await asyncio.to_thread(
146
+ self._sync_graph.complexity, top=top, danger_zone=danger_zone
147
+ )
148
+
149
+ async def deadcode(
150
+ self,
151
+ min_lines: int = 20,
152
+ ) -> DeadCodeReport:
153
+ """Detect unreachable symbols and ghost dependencies asynchronously."""
154
+ return await asyncio.to_thread(
155
+ self._sync_graph.deadcode, min_lines=min_lines
156
+ )
157
+
158
+ async def extract_logic(
159
+ self,
160
+ query: str | None = None,
161
+ symbol: str | None = None,
162
+ concept: str | None = None,
163
+ deep: bool = False,
164
+ ) -> LogicReport:
165
+ """Extract business rules, invariants, and constraints asynchronously."""
166
+ return await asyncio.to_thread(
167
+ self._sync_graph.extract_logic, query=query, symbol=symbol, concept=concept, deep=deep
168
+ )
169
+
170
+ async def diagnose(
171
+ self,
172
+ trace_or_log: str,
173
+ file_path: str | None = None,
174
+ deep: bool = False,
175
+ offline: bool = True,
176
+ ) -> DiagnosisReport:
177
+ """Perform 8-stage topological root-cause fault diagnosis asynchronously."""
178
+ return await asyncio.to_thread(
179
+ self._sync_graph.diagnose,
180
+ trace_or_log=trace_or_log,
181
+ file_path=file_path,
182
+ deep=deep,
183
+ offline=offline,
184
+ )
185
+
186
+ async def diagram(
187
+ self,
188
+ symbol_or_concept: str | None = None,
189
+ diagram_type: str = "architecture",
190
+ format: str = "mermaid",
191
+ depth: int = 2,
192
+ direction: str = "both",
193
+ max_nodes: int = 30,
194
+ collapse_modules: bool = False,
195
+ theme: str = "dark",
196
+ ) -> DiagramResult:
197
+ """Render architecture, call graph, and component diagrams asynchronously."""
198
+ return await asyncio.to_thread(
199
+ self._sync_graph.diagram,
200
+ symbol_or_concept=symbol_or_concept,
201
+ diagram_type=diagram_type,
202
+ format=format,
203
+ depth=depth,
204
+ direction=direction,
205
+ max_nodes=max_nodes,
206
+ collapse_modules=collapse_modules,
207
+ theme=theme,
208
+ )
209
+
210
+ # ── Graph Data Science Integrations ─────────────────────────
211
+
212
+ async def to_networkx(self) -> nx.DiGraph:
213
+ """Stream codebase graph into a NetworkX DiGraph asynchronously."""
214
+ return await asyncio.to_thread(self._sync_graph.to_networkx)
215
+
216
+ async def to_igraph(self) -> ig.Graph:
217
+ """Stream codebase graph into an igraph Graph asynchronously."""
218
+ return await asyncio.to_thread(self._sync_graph.to_igraph)
219
+
220
+ async def nodes_df(self, engine: Literal["polars", "pandas"] = "polars") -> Any:
221
+ """Return nodes dataframe using Polars or Pandas asynchronously."""
222
+ return await asyncio.to_thread(self._sync_graph.nodes_df, engine=engine)
223
+
224
+ async def edges_df(self, engine: Literal["polars", "pandas"] = "polars") -> Any:
225
+ """Return edges dataframe using Polars or Pandas asynchronously."""
226
+ return await asyncio.to_thread(self._sync_graph.edges_df, engine=engine)
227
+
228
+ async def complexity_df(self, engine: Literal["polars", "pandas"] = "polars") -> Any:
229
+ """Return complexity hotspots dataframe using Polars or Pandas asynchronously."""
230
+ return await asyncio.to_thread(self._sync_graph.complexity_df, engine=engine)
231
+
232
+ async def to_polars(self) -> dict[str, pl.DataFrame]:
233
+ """Export all primary tables to Polars DataFrames asynchronously."""
234
+ return await asyncio.to_thread(self._sync_graph.to_polars)
235
+
236
+ async def to_pandas(self) -> dict[str, pd.DataFrame]:
237
+ """Export all primary tables to Pandas DataFrames asynchronously."""
238
+ return await asyncio.to_thread(self._sync_graph.to_pandas)
@@ -0,0 +1,247 @@
1
+ """Synchronous CodeGraph engine interface."""
2
+ from __future__ import annotations
3
+
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING, Any, Literal
6
+
7
+ from cartograph._cartograph import (
8
+ CodeGraph as _NativeCodeGraph,
9
+ ComplexityReport,
10
+ DeadCodeReport,
11
+ DiagnosisReport,
12
+ DiagramResult,
13
+ GraphStats,
14
+ ImpactResult,
15
+ IndexStats,
16
+ LintArchReport,
17
+ LocateResult,
18
+ LogicReport,
19
+ Node,
20
+ RouteTrace,
21
+ TestSelectorResult,
22
+ )
23
+ from cartograph.dataframes import columnar_to_pandas, columnar_to_polars
24
+ from cartograph.igraph_adapter import stream_to_igraph
25
+ from cartograph.networkx_adapter import stream_to_networkx
26
+
27
+ if TYPE_CHECKING:
28
+ import igraph as ig
29
+ import networkx as nx
30
+ import pandas as pd
31
+ import polars as pl
32
+
33
+
34
+ class CodeGraph:
35
+ """High-performance code graph engine and knowledge graph for codebases."""
36
+
37
+ def __init__(
38
+ self,
39
+ path: str | Path | None = None,
40
+ profile: str = "default",
41
+ in_memory: bool = False,
42
+ ) -> None:
43
+ path_str = str(Path(path).resolve()) if path is not None else None
44
+ self._inner = _NativeCodeGraph.open(path=path_str, profile=profile, in_memory=in_memory)
45
+
46
+ @classmethod
47
+ def open(
48
+ cls,
49
+ path: str | Path | None = None,
50
+ profile: str = "default",
51
+ in_memory: bool = False,
52
+ ) -> CodeGraph:
53
+ """Open or initialize a CodeGraph instance."""
54
+ return cls(path=path, profile=profile, in_memory=in_memory)
55
+
56
+ def __enter__(self) -> CodeGraph:
57
+ return self
58
+
59
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
60
+ self.close()
61
+
62
+ def close(self) -> None:
63
+ """Close database connections and release resources."""
64
+ self._inner.close()
65
+
66
+ @property
67
+ def is_open(self) -> bool:
68
+ """Check if database connection is active."""
69
+ return self._inner.is_open()
70
+
71
+ @property
72
+ def profile(self) -> str:
73
+ """Active storage profile name."""
74
+ return self._inner.profile
75
+
76
+ def index(
77
+ self,
78
+ force: bool = False,
79
+ staged: bool = False,
80
+ branch: str | None = None,
81
+ threads: int | None = None,
82
+ ) -> IndexStats:
83
+ """Scan workspace and populate the knowledge graph."""
84
+ return self._inner.index(force=force, staged=staged, branch=branch, threads=threads)
85
+
86
+ def status(self) -> GraphStats:
87
+ """Return aggregate statistics and health of the graph store."""
88
+ return self._inner.status()
89
+
90
+ def locate(
91
+ self,
92
+ query: str,
93
+ code: bool = False,
94
+ limit: int = 10,
95
+ ) -> LocateResult:
96
+ """Natural language or exact code subgraph localization."""
97
+ return self._inner.locate(query=query, code=code, limit=limit)
98
+
99
+ def impact(
100
+ self,
101
+ target: str,
102
+ branch: str | None = None,
103
+ staged: bool = False,
104
+ depth: int = 3,
105
+ ) -> ImpactResult:
106
+ """Perform topological blast-radius and risk analysis."""
107
+ return self._inner.impact(target=target, branch=branch, staged=staged, depth=depth)
108
+
109
+ def test_selector(
110
+ self,
111
+ target: str,
112
+ branch: str | None = None,
113
+ ) -> TestSelectorResult:
114
+ """Predict minimal test set exercising the changed target."""
115
+ return self._inner.test_selector(target=target, branch=branch)
116
+
117
+ def routes(
118
+ self,
119
+ filter_query: str | None = None,
120
+ ) -> list[RouteTrace]:
121
+ """Discover API routes, controller endpoints, and full-stack traces."""
122
+ return self._inner.routes(filter_query=filter_query)
123
+
124
+ def lint_arch(
125
+ self,
126
+ strict: bool = False,
127
+ ) -> LintArchReport:
128
+ """Detect architecture boundary violations and circular dependencies."""
129
+ return self._inner.lint_arch(strict=strict)
130
+
131
+ def complexity(
132
+ self,
133
+ top: int = 15,
134
+ danger_zone: bool = False,
135
+ ) -> ComplexityReport:
136
+ """Analyze cyclomatic/cognitive complexity and test deficits."""
137
+ return self._inner.complexity(top=top, danger_zone=danger_zone)
138
+
139
+ def deadcode(
140
+ self,
141
+ min_lines: int = 20,
142
+ ) -> DeadCodeReport:
143
+ """Detect unreachable symbols and ghost dependencies."""
144
+ return self._inner.deadcode(min_lines=min_lines)
145
+
146
+ def extract_logic(
147
+ self,
148
+ query: str | None = None,
149
+ symbol: str | None = None,
150
+ concept: str | None = None,
151
+ deep: bool = False,
152
+ ) -> LogicReport:
153
+ """Extract business rules, invariants, and constraints."""
154
+ return self._inner.extract_logic(query=query, symbol=symbol, concept=concept, deep=deep)
155
+
156
+ def diagnose(
157
+ self,
158
+ trace_or_log: str,
159
+ file_path: str | None = None,
160
+ deep: bool = False,
161
+ offline: bool = True,
162
+ ) -> DiagnosisReport:
163
+ """Perform 8-stage topological root-cause fault diagnosis."""
164
+ return self._inner.diagnose(
165
+ trace_or_log=trace_or_log, file_path=file_path, deep=deep, offline=offline
166
+ )
167
+
168
+ def diagram(
169
+ self,
170
+ symbol_or_concept: str | None = None,
171
+ diagram_type: str = "architecture",
172
+ format: str = "mermaid",
173
+ depth: int = 2,
174
+ direction: str = "both",
175
+ max_nodes: int = 30,
176
+ collapse_modules: bool = False,
177
+ theme: str = "dark",
178
+ ) -> DiagramResult:
179
+ """Render architecture, call graph, and component diagrams."""
180
+ return self._inner.diagram(
181
+ symbol_or_concept=symbol_or_concept,
182
+ diagram_type=diagram_type,
183
+ format=format,
184
+ depth=depth,
185
+ direction=direction,
186
+ max_nodes=max_nodes,
187
+ collapse_modules=collapse_modules,
188
+ theme=theme,
189
+ )
190
+
191
+ # ── Graph Data Science Integrations ─────────────────────────
192
+
193
+ def to_networkx(self) -> nx.DiGraph:
194
+ """Stream codebase graph into a NetworkX DiGraph."""
195
+ streamer = self._inner.get_streamer()
196
+ return stream_to_networkx(streamer)
197
+
198
+ def to_igraph(self) -> ig.Graph:
199
+ """Stream codebase graph into an igraph Graph."""
200
+ streamer = self._inner.get_streamer()
201
+ return stream_to_igraph(streamer)
202
+
203
+ def nodes_df(self, engine: Literal["polars", "pandas"] = "polars") -> Any:
204
+ """Return nodes dataframe using Polars or Pandas."""
205
+ col_dict = self._inner.nodes_columnar()
206
+ if engine == "polars":
207
+ return columnar_to_polars(col_dict)
208
+ elif engine == "pandas":
209
+ return columnar_to_pandas(col_dict)
210
+ else:
211
+ raise ValueError(f"Unsupported engine: {engine}. Choose 'polars' or 'pandas'")
212
+
213
+ def edges_df(self, engine: Literal["polars", "pandas"] = "polars") -> Any:
214
+ """Return edges dataframe using Polars or Pandas."""
215
+ col_dict = self._inner.edges_columnar()
216
+ if engine == "polars":
217
+ return columnar_to_polars(col_dict)
218
+ elif engine == "pandas":
219
+ return columnar_to_pandas(col_dict)
220
+ else:
221
+ raise ValueError(f"Unsupported engine: {engine}. Choose 'polars' or 'pandas'")
222
+
223
+ def complexity_df(self, engine: Literal["polars", "pandas"] = "polars") -> Any:
224
+ """Return complexity hotspots dataframe using Polars or Pandas."""
225
+ col_dict = self._inner.complexity_columnar()
226
+ if engine == "polars":
227
+ return columnar_to_polars(col_dict)
228
+ elif engine == "pandas":
229
+ return columnar_to_pandas(col_dict)
230
+ else:
231
+ raise ValueError(f"Unsupported engine: {engine}. Choose 'polars' or 'pandas'")
232
+
233
+ def to_polars(self) -> dict[str, pl.DataFrame]:
234
+ """Export all primary tables (nodes, edges, complexity) to Polars DataFrames."""
235
+ return {
236
+ "nodes": self.nodes_df("polars"),
237
+ "edges": self.edges_df("polars"),
238
+ "complexity": self.complexity_df("polars"),
239
+ }
240
+
241
+ def to_pandas(self) -> dict[str, pd.DataFrame]:
242
+ """Export all primary tables (nodes, edges, complexity) to Pandas DataFrames."""
243
+ return {
244
+ "nodes": self.nodes_df("pandas"),
245
+ "edges": self.edges_df("pandas"),
246
+ "complexity": self.complexity_df("pandas"),
247
+ }
@@ -0,0 +1,42 @@
1
+ """Dataframe conversions for Polars, Pandas, and PyArrow."""
2
+ from __future__ import annotations
3
+
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ import pandas as pd
8
+ import polars as pl
9
+ import pyarrow as pa
10
+
11
+
12
+ def columnar_to_polars(col_dict: dict[str, Any]) -> pl.DataFrame:
13
+ """Convert a columnar dictionary directly into a Polars DataFrame."""
14
+ try:
15
+ import polars as pl
16
+ except ImportError as e:
17
+ raise ImportError(
18
+ "polars is not installed. Install it with: pip install 'cartograph[polars]'"
19
+ ) from e
20
+ return pl.DataFrame(col_dict)
21
+
22
+
23
+ def columnar_to_pandas(col_dict: dict[str, Any]) -> pd.DataFrame:
24
+ """Convert a columnar dictionary directly into a Pandas DataFrame."""
25
+ try:
26
+ import pandas as pd
27
+ except ImportError as e:
28
+ raise ImportError(
29
+ "pandas is not installed. Install it with: pip install 'cartograph[pandas]'"
30
+ ) from e
31
+ return pd.DataFrame(col_dict)
32
+
33
+
34
+ def columnar_to_arrow(col_dict: dict[str, Any]) -> pa.Table:
35
+ """Convert a columnar dictionary directly into a PyArrow Table."""
36
+ try:
37
+ import pyarrow as pa
38
+ except ImportError as e:
39
+ raise ImportError(
40
+ "pyarrow is not installed. Install it with: pip install pyarrow"
41
+ ) from e
42
+ return pa.Table.from_pydict(col_dict)
@@ -0,0 +1,51 @@
1
+ """igraph conversion adapter for cartograph."""
2
+ from __future__ import annotations
3
+
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ import igraph as ig
8
+
9
+
10
+ def stream_to_igraph(streamer: Any) -> ig.Graph:
11
+ """Stream graph nodes and edges directly into an igraph Graph."""
12
+ try:
13
+ import igraph as ig
14
+ except ImportError as e:
15
+ raise ImportError(
16
+ "igraph is not installed. Install it with: pip install 'cartograph[igraph]'"
17
+ ) from e
18
+
19
+ nodes = streamer.get_nodes()
20
+ edges = streamer.get_edges()
21
+
22
+ node_indices = {n[0]: i for i, n in enumerate(nodes)}
23
+ edge_tuples = []
24
+ edge_kinds = []
25
+ edge_weights = []
26
+
27
+ for src, tgt, kind, weight in edges:
28
+ if src in node_indices and tgt in node_indices:
29
+ edge_tuples.append((node_indices[src], node_indices[tgt]))
30
+ edge_kinds.append(kind)
31
+ edge_weights.append(weight)
32
+
33
+ g = ig.Graph(
34
+ n=len(nodes),
35
+ edges=edge_tuples,
36
+ directed=True,
37
+ vertex_attrs={
38
+ "name": [n[0] for n in nodes],
39
+ "symbol_name": [n[1] for n in nodes],
40
+ "kind": [n[2] for n in nodes],
41
+ "filepath": [n[3] for n in nodes],
42
+ "start_line": [n[4] for n in nodes],
43
+ "end_line": [n[5] for n in nodes],
44
+ "complexity": [n[6] for n in nodes],
45
+ },
46
+ edge_attrs={
47
+ "kind": edge_kinds,
48
+ "weight": edge_weights,
49
+ },
50
+ )
51
+ return g
cartograph/jupyter.py ADDED
@@ -0,0 +1,38 @@
1
+ """Jupyter and IPython display integrations for cartograph."""
2
+ from __future__ import annotations
3
+
4
+ import html
5
+ from typing import Any
6
+
7
+
8
+ def render_mermaid_html(mermaid_code: str) -> str:
9
+ """Render a mermaid diagram inside Jupyter / IPython notebook via HTML."""
10
+ escaped = html.escape(mermaid_code)
11
+ return f"""
12
+ <div class="cartograph-mermaid-container" style="background: #1e1e2e; padding: 16px; border-radius: 8px;">
13
+ <pre class="mermaid" style="background: transparent;">
14
+ {escaped}
15
+ </pre>
16
+ <script type="module">
17
+ import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
18
+ mermaid.initialize({{ startOnLoad: true, theme: 'dark' }});
19
+ mermaid.run();
20
+ </script>
21
+ </div>
22
+ """
23
+
24
+
25
+ class RichMermaidDisplay:
26
+ """Wrapper that displays mermaid diagrams natively in Jupyter."""
27
+
28
+ def __init__(self, content: str):
29
+ self.content = content
30
+
31
+ def _repr_html_(self) -> str:
32
+ return render_mermaid_html(self.content)
33
+
34
+ def __str__(self) -> str:
35
+ return self.content
36
+
37
+ def __repr__(self) -> str:
38
+ return self.content
cartograph/models.py ADDED
@@ -0,0 +1,64 @@
1
+ """Data models and exception classes for Cartograph."""
2
+ from __future__ import annotations
3
+
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from cartograph._cartograph import (
7
+ AnalysisError,
8
+ BoundaryViolation,
9
+ BusinessRule,
10
+ CartographError,
11
+ ComplexityRecord,
12
+ ComplexityReport,
13
+ DatabaseError,
14
+ DeadCodeReport,
15
+ DeadSymbolItem,
16
+ DependencyCycle,
17
+ DiagnosisReport,
18
+ DiagramResult,
19
+ Edge,
20
+ FaultCandidate,
21
+ GraphStats,
22
+ GraphStreamer,
23
+ ImpactResult,
24
+ ImpactRoot,
25
+ IndexStats,
26
+ LintArchReport,
27
+ LocateResult,
28
+ LogicReport,
29
+ Node,
30
+ RouteTrace,
31
+ SelectedTest,
32
+ SymbolNotFoundError,
33
+ TestSelectorResult,
34
+ )
35
+
36
+ __all__ = [
37
+ "AnalysisError",
38
+ "BoundaryViolation",
39
+ "BusinessRule",
40
+ "CartographError",
41
+ "ComplexityRecord",
42
+ "ComplexityReport",
43
+ "DatabaseError",
44
+ "DeadCodeReport",
45
+ "DeadSymbolItem",
46
+ "DependencyCycle",
47
+ "DiagnosisReport",
48
+ "DiagramResult",
49
+ "Edge",
50
+ "FaultCandidate",
51
+ "GraphStats",
52
+ "GraphStreamer",
53
+ "ImpactResult",
54
+ "ImpactRoot",
55
+ "IndexStats",
56
+ "LintArchReport",
57
+ "LocateResult",
58
+ "LogicReport",
59
+ "Node",
60
+ "RouteTrace",
61
+ "SelectedTest",
62
+ "SymbolNotFoundError",
63
+ "TestSelectorResult",
64
+ ]