Flows
flows
Execution flow tracing via entry point detection and BFS call graph.
Detects framework-specific entry points (cyclopts, click, Flask, FastAPI,
pytest, __main__ guards) and traces execution flows through the
call graph using BFS.
Example::
>>> from axm_ast.core.analyzer import analyze_package
>>> from axm_ast.core.flows import find_entry_points, trace_flow
>>> pkg = analyze_package(Path("src/mylib"))
>>> entries = find_entry_points(pkg)
>>> for e in entries:
... print(f"{e.framework}: {e.name} ({e.module}:{e.line})")
EntryPoint
Bases: BaseModel
A detected entry point in the codebase.
Source code in packages/axm-ast/src/axm_ast/core/flows.py
FlowStep
Bases: BaseModel
A single step in a traced execution flow.
Source code in packages/axm-ast/src/axm_ast/core/flows.py
build_callee_index(pkg)
Pre-compute a callee index for the entire package in one pass.
Instead of scanning all modules per symbol (O(modules x AST) per BFS step),
this builds a {(module, symbol): [CallSite]} dict in a single pass.
BFS then uses O(1) dict lookups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pkg
|
PackageInfo
|
Analyzed package info. |
required |
Returns:
| Type | Description |
|---|---|
dict[tuple[str, str], list[CallSite]]
|
Dict mapping |
Source code in packages/axm-ast/src/axm_ast/core/flows.py
find_callees(pkg, symbol, *, _parse_cache=None)
Find all functions called by a given symbol (forward call graph).
This is the inverse of find_callers: instead of asking "who calls X?",
it asks "what does X call?".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pkg
|
PackageInfo
|
Analyzed package info. |
required |
symbol
|
str
|
Name of the function/method to inspect. |
required |
_parse_cache
|
dict[str, tuple[Any, str]] | None
|
Optional cache of |
None
|
Returns:
| Type | Description |
|---|---|
list[CallSite]
|
List of CallSite objects for each call made by the symbol. |
Example
callees = find_callees(pkg, "main") for c in callees: ... print(f" calls {c.symbol} at {c.module}:{c.line}")
Source code in packages/axm-ast/src/axm_ast/core/flows.py
find_entry_points(pkg)
Detect framework-registered entry points across a package.
Scans for:
- Decorator-based: cyclopts, click, Flask, FastAPI
- Test functions:
test_*prefix - Main guards:
if __name__ == "__main__"blocks __all__exports
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pkg
|
PackageInfo
|
Analyzed package info. |
required |
Returns:
| Type | Description |
|---|---|
list[EntryPoint]
|
List of EntryPoint objects sorted by module then line. |
Source code in packages/axm-ast/src/axm_ast/core/flows.py
format_flows(entry_points)
Format entry point results as human-readable grouped output.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entry_points
|
list[EntryPoint]
|
List of detected entry points. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Formatted string grouped by framework. |
Source code in packages/axm-ast/src/axm_ast/core/flows.py
trace_flow(pkg, entry, *, max_depth=5, cross_module=False, detail='trace', callee_index=None, exclude_stdlib=True)
Trace execution flow from an entry point via BFS.
Follows the forward call graph from entry up to max_depth levels deep. Uses a visited set to handle circular calls.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pkg
|
PackageInfo
|
Analyzed package info. |
required |
entry
|
str
|
Name of the entry point function to trace from. |
required |
max_depth
|
int
|
Maximum BFS depth (default 5). |
5
|
cross_module
|
bool
|
If True, resolve imports and continue BFS into external modules on-demand. |
False
|
detail
|
str
|
Level of detail — |
'trace'
|
callee_index
|
dict[tuple[str, str], list[CallSite]] | None
|
Optional pre-computed index from
:func: |
None
|
exclude_stdlib
|
bool
|
If True (default), skip callees whose name
matches a stdlib module or Python builtin (e.g. |
True
|
Returns:
| Type | Description |
|---|---|
list[FlowStep]
|
List of FlowStep objects ordered by depth then discovery. |
Example
steps = trace_flow(pkg, "main", max_depth=3) for s in steps: ... print(f"{' ' * s.depth}{s.name} ({s.module}:{s.line})")
Source code in packages/axm-ast/src/axm_ast/core/flows.py
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 | |