Trace a single execution flow from *ep* via forward BFS. Returns a flow dict (see :func:`trace_flows` for the schema) or ``None`` if the flow is trivial (single-node, no outgoing CALLS that resolve).
(
adj: FlowAdjacency,
ep: GraphNode,
max_depth: int = 15,
)
| 204 | |
| 205 | |
| 206 | def _trace_single_flow( |
| 207 | adj: FlowAdjacency, |
| 208 | ep: GraphNode, |
| 209 | max_depth: int = 15, |
| 210 | ) -> Optional[dict]: |
| 211 | """Trace a single execution flow from *ep* via forward BFS. |
| 212 | |
| 213 | Returns a flow dict (see :func:`trace_flows` for the schema) or ``None`` |
| 214 | if the flow is trivial (single-node, no outgoing CALLS that resolve). |
| 215 | """ |
| 216 | path_ids: list[int] = [ep.id] |
| 217 | path_qnames: list[str] = [ep.qualified_name] |
| 218 | visited: set[str] = {ep.qualified_name} |
| 219 | queue: deque[tuple[str, int]] = deque([(ep.qualified_name, 0)]) |
| 220 | |
| 221 | actual_depth = 0 |
| 222 | nodes_by_qn = adj.nodes_by_qn |
| 223 | calls_out = adj.calls_out |
| 224 | |
| 225 | while queue: |
| 226 | current_qn, depth = queue.popleft() |
| 227 | if depth > actual_depth: |
| 228 | actual_depth = depth |
| 229 | if depth >= max_depth: |
| 230 | continue |
| 231 | |
| 232 | for target_qn in calls_out.get(current_qn, ()): |
| 233 | if target_qn in visited: |
| 234 | continue |
| 235 | target_node = nodes_by_qn.get(target_qn) |
| 236 | if target_node is None: |
| 237 | continue |
| 238 | visited.add(target_qn) |
| 239 | path_ids.append(target_node.id) |
| 240 | path_qnames.append(target_qn) |
| 241 | queue.append((target_qn, depth + 1)) |
| 242 | |
| 243 | # Skip trivial single-node flows. |
| 244 | if len(path_ids) < 2: |
| 245 | return None |
| 246 | |
| 247 | files = list({ |
| 248 | n.file_path |
| 249 | for qn in path_qnames |
| 250 | if (n := nodes_by_qn.get(qn)) is not None |
| 251 | }) |
| 252 | |
| 253 | flow: dict = { |
| 254 | "name": _sanitize_name(ep.name), |
| 255 | "entry_point": ep.qualified_name, |
| 256 | "entry_point_id": ep.id, |
| 257 | "path": path_ids, |
| 258 | "depth": actual_depth, |
| 259 | "node_count": len(path_ids), |
| 260 | "file_count": len(files), |
| 261 | "files": files, |
| 262 | "criticality": 0.0, |
| 263 | } |
no test coverage detected