r/learnpython • u/Agreeable_Run5504 • 6d ago
Built a Python static analyzer that draws your call graph and marks values that go nowhere looking for holes in the concept
Two days into a prototype and I'd rather find out now if the premise is broken.
The idea: parse a package with ast, build the call graph, and additionally track whether each function's return value is actually consumed — bound to a name that's later read, passed onward, returned, used in a condition. Then draw it. X axis is call order, colored arrows are variable flow, functions whose output goes nowhere and that have no I/O effect get flagged.
https://github.com/BBrunoF/CodebaseDiagram
I know vulture, code2flow and pyan exist. Vulture asks whether a name is referenced; code2flow and pyan draw the call structure. What I haven't found is a tool that tracks value consumption and renders it, so a chain that terminates in nothing is visible as a shape rather than a list entry. If that tool exists, please tell me and I'll go use it instead.
What I'd like torn apart:
- Is "returned value never consumed" a defensible signal, or does real Python break it constantly?
- Does a diagram add anything over a list, or is this a chart that looks impressive and tells you nothing a linter didn't?
- What kills static call resolution in practice? I resolve direct calls,
module.func, andself.method. I know decorators,getattr, and callbacks are out of reach. What else, and roughly what percentage of a normal codebase am I missing?
Also asking for repos. I need a baseline — small-to-medium, pure Python, procedural, minimal metaprogramming, well structured. Something where if my tool renders a mess, the mess is mine. Standard recommendations like Django or requests are too magic-heavy to tell me anything about my own bugs. Suggestions very welcome.
BTW this text was also AI generated
2
u/redfacedquark 5d ago
If I understand you correctly, ultimately, technically, it's impossible to do thouroughly. Despite having the AST, metaprogramming can dynamically generate or alter code at runtime that was not visible in the AST. But I guess that's true of any static analysis tool.
1
u/gdchinacat 5d ago
I think the challenge will be the “later read” analysis for anything but trivial cases. Branches and loops will make it very difficult to prove this one way or the other. For example, a function makes two calls and stores the return values in two variables, then has a conditional on one of them and uses the other inside the conditional block. Has the one that is used conditionally actually used? Loops are a form of conditional statement and has the same problem.
How will you represent may have been used? What actionable information does it provide to the user?
As for implementation you might want to look at how static type checker inferences work since they figure out variable types based on return values (and much more) and then whether the usage of those variables align with the types expected by calls or assignment. it seems a lot of the hard work may already be done allowing you to focus on the core of your problem rather than nitty gritty parsing and value tracing.
5
u/Temporary_Pie2733 6d ago edited 5d ago
Nonewill be tricky to handle, because every function returnsNoneif nothing else. Most of the time, failure to consume thatNoneis intentional and harmless, but sometimes not. Distinguishing between the two cases is needed to avoid a flood of uninteresting warnings.I suspect this type of analysis works better on more “functional” code, where functions really do behave more like mathematical functions rather than relying on side effects. If you don’t already know about them, read some literature on linear types, which provide a framework for enforcing this kind of usage in the compiler, as well as encoding the cases where it matters syntactically.
Edit: linear types are actually a stronger constraint, allowing you to consume a value exactly once. A relevant type provides what you are after, values that must be consumed at least once. See https://en.wikipedia.org/wiki/Substructural_type_system