Code2flow generates call graphs for dynamic programming language. Code2flow supports Python, JavaScript, Ruby, and PHP.
The basic algorithm is simple:
Code2flow is useful for:
Code2flow provides a pretty good estimate of your project's structure. No algorithm can generate a perfect call graph for a dynamic language – even less so if that language is duck-typed. See the known limitations in the section below.
(Below: Code2flow running against a subset of itself code2flow code2flow/engine.py code2flow/python.py --target-function=code2flow --downstream-depth=3
)
pip3 install code2flow
If you don't have it already, you will also need to install graphviz. Installation instructions can be found here.
Additionally, depending on the language you want to parse, you may need to install additional dependencies:
To generate a DOT file, run something like:
code2flow mypythonfile.py
Or, for Javascript:
code2flow myjavascriptfile.js
You can specify multiple files or import directories:
code2flow project/directory/source_a.js project/directory/source_b.js
code2flow project/directory/*.js
code2flow project/directory --language js
To pull out a subset of the graph, try something like:
code2flow mypythonfile.py --target-function my_func --upstream-depth=1 --downstream-depth=1
There are a ton of command line options, to see them all, run:
code2flow --help
Code2flow approximates the structure of projects in dynamic languages. It is not possible to generate a perfect callgraph for a dynamic language.
Detailed algorithm:
Consider this toy example in Python
def func_factory(param):
if param < .5:
return func_a
else:
return func_b
func = func_factory(important_variable)
func()
We have no way of knowing whether func
will point to func_a
or func_b
until runtime. In practice, ambiguity like this is common and is present in most non-trivial applications.
Code2flow is internally powered by ASTs. Most limitations stem from a token not being named what code2flow expects it to be named.
search()
and call, import searcher; searcher.search()
, code2flow may link (incorrectly) to your defined function.You can work with code2flow as an imported Python library in much the same way as you work with it from the CLI.
import code2flow
code2flow.code2flow(['path/to/filea', 'path/to/fileb'], 'path/to/outputfile')
The keyword arguments to code2flow.code2flow
are roughly the same as the CLI
parameters. To see all available parameters, refer to the code2flow function in engine.py.
Test coverage is 100%. To run:
pip install -r requirements_dev.txt
make test
Code2flow is licensed under the MIT license. Prior to the rewrite in April 2021, code2flow was licensed under LGPL. The last commit under that license was 24b2cb854c6a872ba6e17409fbddb6659bf64d4c. The April 2021 rewrite was substantial, so it's probably reasonable to treat code2flow as completely MIT-licensed.
The name, "code2flow", has been used for several unrelated projects. Specifically, the domain, code2flow.com, has no association with this project. I've never heard anything from them and it doesn't appear like they use anything from here.
If you have an issue using code2flow or a feature request, please post it in the issues tab. In general, I don't provide help over email. Answering a question publicly helps way more people. For everything else, please do email! scottmrogowski@gmail.com
Email me. Usually, I'm spread thin across a lot of projects, so I will, unfortunately, turn down most requests. However, I am open to paid development for compelling features.