Pyan3 - Offline call graph generator for Python 3

Overview

Pyan3

Offline call graph generator for Python 3

Build Status FOSSA Status Codacy Badge PyPI - Python Version

Pyan takes one or more Python source files, performs a (rather superficial) static analysis, and constructs a directed graph of the objects in the combined source, and how they define or use each other. The graph can be output for rendering by GraphViz or yEd.

This project has 2 official repositories:

The PyPI package pyan3 is built from development

About

Example output

Defines relations are drawn with dotted gray arrows.

Uses relations are drawn with black solid arrows. Recursion is indicated by an arrow from a node to itself. Mutual recursion between nodes X and Y is indicated by a pair of arrows, one pointing from X to Y, and the other from Y to X.

Nodes are always filled, and made translucent to clearly show any arrows passing underneath them. This is especially useful for large graphs with GraphViz's fdp filter. If colored output is not enabled, the fill is white.

In node coloring, the HSL color model is used. The hue is determined by the filename the node comes from. The lightness is determined by depth of namespace nesting, with darker meaning more deeply nested. Saturation is constant. The spacing between different hues depends on the number of files analyzed; better results are obtained for fewer files.

Groups are filled with translucent gray to avoid clashes with any node color.

The nodes can be annotated by filename and source line number information.

Note

The static analysis approach Pyan takes is different from running the code and seeing which functions are called and how often. There are various tools that will generate a call graph that way, usually using a debugger or profiling trace hooks, such as Python Call Graph.

In Pyan3, the analyzer was ported from compiler (good riddance) to a combination of ast and symtable, and slightly extended.

Install

pip install pyan3

Usage

See pyan3 --help.

Example:

pyan *.py --uses --no-defines --colored --grouped --annotated --dot >myuses.dot

Then render using your favorite GraphViz filter, mainly dot or fdp:

dot -Tsvg myuses.dot >myuses.svg

Or use directly

pyan *.py --uses --no-defines --colored --grouped --annotated --svg >myuses.svg

You can also export as an interactive HTML

pyan *.py --uses --no-defines --colored --grouped --annotated --html > myuses.html

Alternatively, you can call pyan from a script

import pyan
from IPython.display import HTML
HTML(pyan.create_callgraph(filenames="**/*.py", format="html"))

Sphinx integration

You can integrate callgraphs into Sphinx. Install graphviz (e.g. via sudo apt-get install graphviz) and modify source/conf.py so that

# modify extensions
extensions = [
  ...
  "sphinx.ext.graphviz"
  "pyan.sphinx",
]

# add graphviz options
graphviz_output_format = "svg"

Now, there is a callgraph directive which has all the options of the graphviz directive and in addition:

  • :no-groups: (boolean flag): do not group
  • :no-defines: (boolean flag): if to not draw edges that show which functions, methods and classes are defined by a class or module
  • :no-uses: (boolean flag): if to not draw edges that show how a function uses other functions
  • :no-colors: (boolean flag): if to not color in callgraph (default is coloring)
  • :nested-grops: (boolean flag): if to group by modules and submodules
  • :annotated: (boolean flag): annotate callgraph with file names
  • :direction: (string): "horizontal" or "vertical" callgraph
  • :toctree: (string): path to toctree (as used with autosummary) to link elements of callgraph to documentation (makes all nodes clickable)
  • :zoomable: (boolean flag): enables users to zoom and pan callgraph

Example to create a callgraph for the function pyan.create_callgraph that is zoomable, is defined from left to right and links each node to the API documentation that was created at the toctree path api.

.. callgraph:: pyan.create_callgraph
   :toctree: api
   :zoomable:
   :direction: horizontal

Troubleshooting

If GraphViz says trouble in init_rank, try adding -Gnewrank=true, as in:

dot -Gnewrank=true -Tsvg myuses.dot >myuses.svg

Usually either old or new rank (but often not both) works; this is a long-standing GraphViz issue with complex graphs.

Too much detail?

If the graph is visually unreadable due to too much detail, consider visualizing only a subset of the files in your project. Any references to files outside the analyzed set will be considered as undefined, and will not be drawn.

Currently Pyan always operates at the level of individual functions and methods; an option to visualize only relations between namespaces may (or may not) be added in a future version.

Features

Items tagged with ☆ are new in Pyan3.

Graph creation:

  • Nodes for functions and classes
  • Edges for defines
  • Edges for uses
    • This includes recursive calls ☆
  • Grouping to represent defines, with or without nesting
  • Coloring of nodes by filename
    • Unlimited number of hues ☆

Analysis:

  • Name lookup across the given set of files
  • Nested function definitions
  • Nested class definitions ☆
  • Nested attribute accesses like self.a.b
  • Inherited attributes ☆
    • Pyan3 looks up also in base classes when resolving attributes. In the old Pyan, calls to inherited methods used to be picked up by contract_nonexistents() followed by expand_unknowns(), but that often generated spurious uses edges (because the wildcard to *.name expands to X.name for all X that have an attribute called name.).
  • Resolution of super() based on the static type at the call site ☆
  • MRO is (statically) respected in looking up inherited attributes and super()
  • Assignment tracking with lexical scoping
    • E.g. if self.a = MyFancyClass(), the analyzer knows that any references to self.a point to MyFancyClass
    • All binding forms are supported (assign, augassign, for, comprehensions, generator expressions, with) ☆
      • Name clashes between for loop counter variables and functions or classes defined elsewhere no longer confuse Pyan.
  • self is defined by capturing the name of the first argument of a method definition, like Python does. ☆
  • Simple item-by-item tuple assignments like x,y,z = a,b,c
  • Chained assignments a = b = c
  • Local scope for lambda, listcomp, setcomp, dictcomp, genexpr ☆
    • Keep in mind that list comprehensions gained a local scope (being treated like a function) only in Python 3. Thus, Pyan3, when applied to legacy Python 2 code, will give subtly wrong results if the code uses list comprehensions.
  • Source filename and line number annotation ☆
    • The annotation is appended to the node label. If grouping is off, namespace is included in the annotation. If grouping is on, only source filename and line number information is included, because the group title already shows the namespace.

TODO

  • Determine confidence of detected edges (probability that the edge is correct). Start with a binary system, with only values 1.0 and 0.0.
    • A fully resolved reference to a name, based on lexical scoping, has confidence 1.0.
    • A reference to an unknown name has confidence 0.0.
    • Attributes:
      • A fully resolved reference to a known attribute of a known object has confidence 1.0.
      • A reference to an unknown attribute of a known object has confidence 1.0. These are mainly generated by imports, when the imported file is not in the analyzed set. (Does this need a third value, such as 0.5?)
      • A reference to an attribute of an unknown object has confidence 0.0.
    • A wildcard and its expansions have confidence 0.0.
    • Effects of binding analysis? The system should not claim full confidence in a bound value, unless it fully understands both the binding syntax and the value. (Note that this is very restrictive. A function call or a list in the expression for the value will currently spoil the full analysis.)
    • Confidence values may need updating in pass 2.
  • Make the analyzer understand del name (probably seen as isinstance(node.ctx, ast.Del) in visit_Name(), visit_Attribute())
  • Prefix methods by class name in the graph; create a legend for annotations. See the discussion here.
  • Improve the wildcard resolution mechanism, see discussion here.
    • Could record the namespace of the use site upon creating the wildcard, and check any possible resolutions against that (requiring that the resolved name is in scope at the use site)?
  • Add an option to visualize relations only between namespaces, useful for large projects.
    • Scan the nodes and edges, basically generate a new graph and visualize that.
  • Publish test cases.
  • Get rid of self.last_value?
    • Consider each specific kind of expression or statement being handled; get the relevant info directly (or by a more controlled kind of recursion) instead of self.visit().
    • At some point, may need a second visitor class that is just a catch-all that extracts names, which is then applied to only relevant branches of the AST.
    • On the other hand, maybe self.last_value is the simplest implementation that extracts a value from an expression, and it only needs to be used in a controlled manner (as analyze_binding() currently does); i.e. reset before visiting, and reset immediately when done.

The analyzer does not currently support:

  • Tuples/lists as first-class values (currently ignores any assignment of a tuple/list to a single name).
    • Support empty lists, too (for resolving method calls to .append() and similar).
  • Starred assignment a,*b,c = d,e,f,g,h
  • Slicing and indexing in assignment (ast.Subscript)
  • Additional unpacking generalizations (PEP 448, Python 3.5+).
    • Any uses on the RHS at the binding site in all of the above are already detected by the name and attribute analyzers, but the binding information from assignments of these forms will not be recorded (at least not correctly).
  • Enums; need to mark the use of any of their attributes as use of the Enum. Need to detect Enum in bases during analysis of ClassDef; then tag the class as an enum and handle differently.
  • Resolving results of function calls, except for a very limited special case for super().
    • Any binding of a name to a result of a function (or method) call - provided that the binding itself is understood by Pyan - will instead show in the output as binding the name to that function (or method). (This may generate some unintuitive uses edges in the graph.)
  • Distinguishing between different Lambdas in the same namespace (to report uses of a particular lambda that has been stored in self.something).
  • Type hints (PEP 484, Python 3.5+).
  • Type inference for function arguments
    • Either of these two could be used to bind function argument names to the appropriate object types, avoiding the need for wildcard references (especially for attribute accesses on objects passed in as function arguments).
    • Type inference could run as pass 3, using additional information from the state of the graph after pass 2 to connect call sites to function definitions. Alternatively, no additional pass; store the AST nodes in the earlier pass. Type inference would allow resolving some wildcards by finding the method of the actual object instance passed in.
    • Must understand, at the call site, whether the first positional argument in the function def is handled implicitly or not. This is found by looking at the flavor of the Node representing the call target.
  • Async definitions are detected, but passed through to the corresponding non-async analyzers; could be annotated.
  • Cython; could strip or comment out Cython-specific code as a preprocess step, then treat as Python (will need to be careful to get line numbers right).

How it works

From the viewpoint of graphing the defines and uses relations, the interesting parts of the AST are bindings (defining new names, or assigning new values to existing names), and any name that appears in an ast.Load context (i.e. a use). The latter includes function calls; the function's name then appears in a load context inside the ast.Call node that represents the call site.

Bindings are tracked, with lexical scoping, to determine which type of object, or which function, each name points to at any given point in the source code being analyzed. This allows tracking things like:

def some_func():
    pass

class MyClass:
    def __init__(self):
        self.f = some_func

    def dostuff(self)
        self.f()

By tracking the name self.f, the analyzer will see that MyClass.dostuff() uses some_func().

The analyzer also needs to keep track of what type of object self currently points to. In a method definition, the literal name representing self is captured from the argument list, as Python does; then in the lexical scope of that method, that name points to the current class (since Pyan cares only about object types, not instances).

Of course, this simple approach cannot correctly track cases where the current binding of self.f depends on the order in which the methods of the class are executed. To keep things simple, Pyan decides to ignore this complication, just reads through the code in a linear fashion (twice so that any forward-references are picked up), and uses the most recent binding that is currently in scope.

When a binding statement is encountered, the current namespace determines in which scope to store the new value for the name. Similarly, when encountering a use, the current namespace determines which object type or function to tag as the user.

Authors

See AUTHORS.md.

License

GPL v2, as per comments here.

Comments
  • pyan3 is crashing all the time

    pyan3 is crashing all the time

    Every time i try pyan3 on different projects it crash with the following results

    $ pyan3 sun.py
    Traceback (most recent call last):
      File "c:\users\anders\anaconda3\envs\py36\lib\runpy.py", line 193, in _run_module_as_main
        "__main__", mod_spec)
      File "c:\users\anders\anaconda3\envs\py36\lib\runpy.py", line 85, in _run_code
        exec(code, run_globals)
      File "C:\Users\anders\anaconda3\envs\py36\Scripts\pyan3.exe\__main__.py", line 7, in <module>
      File "c:\users\anders\anaconda3\envs\py36\lib\site-packages\pyan\main.py", line 206, in main
        v = CallGraphVisitor(filenames, logger, root=root)
    TypeError: __init__() got multiple values for argument 'root'
    
    

    Any ideas how to fix this?

    I tried it on both Python 3.6 and 3.8 with the same results.

    bug 
    opened by simbalsyd 12
  • Resolve `from` imports

    Resolve `from` imports

    This PR addresses import such as from mod_x import func_y as func_z and from mod_x import mod_y. Relative imports such as from ..mod_x import mod_y are not supported. However, relative imports are considered bad style and discouraged. It's probably not too much work to add this functionality.

    As the package structure has to be known to resolve imports, this is done as a post-processing step relinking the modules.

    opened by jdb78 9
  • RuntimeError: dictionary changed size during iteration

    RuntimeError: dictionary changed size during iteration

    Getting this on a specific directory (not seeing it elsewhere) What do you need to dig into this?

    Traceback (most recent call last): File "/Users/nevep/.pyenv/bin/versions/3.7.4/envs/egs-api/bin/pyan3", line 7, in exec(compile(f.read(), file, 'exec')) File "/Users/nevep/bepress/pyan/pyan3", line 11, in sys.exit(main()) File "/Users/nevep/bepress/pyan/pyan/main.py", line 109, in main v = CallGraphVisitor(filenames, logger) File "/Users/nevep/bepress/pyan/pyan/analyzer.py", line 77, in init self.process() File "/Users/nevep/bepress/pyan/pyan/analyzer.py", line 87, in process self.postprocess() File "/Users/nevep/bepress/pyan/pyan/analyzer.py", line 154, in postprocess self.collapse_inner() File "/Users/nevep/bepress/pyan/pyan/analyzer.py", line 1562, in collapse_inner for name in self.nodes: RuntimeError: dictionary changed size during iteration

    bug 
    opened by pmneve 8
  • Installing pyan3

    Installing pyan3

    Hello, and sorry if my errors are obvious, I'm relativly new. So after installing pyan3 using pip install pyan3 I don't find a way to put it into the PATH of windows 10 so I can use the projet with powershell like in the guidelines pyan *.py --uses --no-defines --colored --grouped --annotated --dot >myuses.dot I tried to put the directory into the PATH "C:\ProgramData\Anaconda3\Lib\site-packages\pyan" or "C:\ProgramData\Anaconda3\Lib\site-packages" and it didn't work

    Thanks in advance for anyone who will read and put they minds into it, and sorry if it's a stupid error and my part, anyway, have a good day

    question 
    opened by Djaningo 7
  • Requirements on python files? -- failing to graph

    Requirements on python files? -- failing to graph

    Hello, I'm having issues with pyan. Specifically, when I try to graph my python files, I get blank graph. I tested pyan with a simple test.py file and it works fine, but my large program shows nothing. Is there specific programming style it expects? I'm not sure if this is a style issue, or an issue with I have an associated library it calls ? or something else. The only thing I can think of is I have a weird mix of global variables and calls to classes in my library file.

    When I put both the library and my main file on the command line calling pyan , it graphs only the library file. Does that seem right?

    I can't post the code it is private.

    I have python 3.8 on windows 64 bit.

    question 
    opened by sk3499 6
  • IndexError in visit_AnnAssign

    IndexError in visit_AnnAssign

    Hi.

    trying to run pyan against my code, it crashes with this error:

    pyan3 *.py --uses --no-defines --colored --grouped --annotated --svg >myuses.svg
    Traceback (most recent call last):
      File "/home/<user>/.local/bin/pyan3", line 11, in <module>
        sys.exit(main())
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/main.py", line 235, in main
        v = CallGraphVisitor(filenames, logger)
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/analyzer.py", line 75, in __init__
        self.process()
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/analyzer.py", line 82, in process
        self.process_one(filename)
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/analyzer.py", line 96, in process_one
        self.visit(ast.parse(content, filename))
      File "/usr/lib64/python3.6/ast.py", line 253, in visit
        return visitor(node)
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/analyzer.py", line 340, in visit_Module
        self.generic_visit(node)  # visit the **children** of node
      File "/usr/lib64/python3.6/ast.py", line 261, in generic_visit
        self.visit(item)
      File "/usr/lib64/python3.6/ast.py", line 253, in visit
        return visitor(node)
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/analyzer.py", line 386, in visit_ClassDef
        self.visit(stmt)
      File "/usr/lib64/python3.6/ast.py", line 253, in visit
        return visitor(node)
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/analyzer.py", line 463, in visit_AsyncFunctionDef
        self.visit_FunctionDef(node)  # TODO: alias for now; tag async functions in output in a future version?
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/analyzer.py", line 454, in visit_FunctionDef
        self.visit(stmt)
      File "/usr/lib64/python3.6/ast.py", line 253, in visit
        return visitor(node)
      File "/home/<user>/.local/lib/python3.6/site-packages/pyan/analyzer.py", line 752, in visit_AnnAssign
        get_ast_node_name(value[0]),
    IndexError: list index out of range
    
    

    Cannot share my code, but if I could do something else to help you in debugging, just let me know

    bug 
    opened by njordr 5
  • Syntax error give by pyan

    Syntax error give by pyan

    @Technologicat hi thanks for working on pyan , currently i face issues for higher version of python3.6 which has different syntax as shown below

    print(f"Kitti info train file is saved to {filename}") SyntaxError: invalid syntax

    How to solve this ??

    question 
    opened by abhigoku10 5
  • Relative imports crash pyan

    Relative imports crash pyan

    Pyan does not currently support from . import foo, and crashes when it sees one.

    For relative imports, the module attribute of the ImportFrom node is None.

    We need to detect this case, and then also handle the level attribute, and actually figure out the correct absolute module path (at least as far as Pyan can reasonably detect) based on the relative one.

    See GTS on imports.

    bug 
    opened by Technologicat 5
  • __init__() got multiple values for argument 'root'

    __init__() got multiple values for argument 'root'

    Issue Calling pyan3 from command line exits with a TypeError

    Traceback (most recent call last):
      File "/usr/lib/python3.7/runpy.py", line 193, in _run_module_as_main
        "__main__", mod_spec)
      File "/usr/lib/python3.7/runpy.py", line 85, in _run_code
        exec(code, run_globals)
      File "/usr/local/lib/python3.7/dist-packages/pyan/main.py", line 244, in <module>
        main()
      File "/usr/local/lib/python3.7/dist-packages/pyan/main.py", line 206, in main
        v = CallGraphVisitor(filenames, logger, root=root)
    TypeError: __init__() got multiple values for argument 'root'
    

    To reproduce Install using pip and git master: pip3 install git+https://github.com/Technologicat/pyan.git Run pyan3 with parameters: pyan3 application.py --dot > test.dot

    Environment Python 3.7.10 VIrtualEnv on Ubuntu 21.04

    opened by ALeyshon 4
  • Asserts can be removed during bytecode optimization

    Asserts can be removed during bytecode optimization

    From Codacy issues

    assert is removed with compiling to optimised byte code (python -o producing *.pyo files). This caused various protections to be removed. The use of assert is also considered as general bad practice in OpenStack codebases.

    Link to list all occurrences: https://app.codacy.com/manual/edumco/pyan/issues/index?bid=15369107

    opened by edumco 4
  • pip install from pypi is broken for venvs

    pip install from pypi is broken for venvs

    Here is what I got when installed in fresh temporary python venv:

    ➜  ~ mktmpenv --python=/usr/bin/python3
    Already using interpreter /usr/bin/python3
    Using base prefix '/usr'
    New python executable in /home/ttylec/.virtualenvs/tmp-195183325368ab1e/bin/python3
    Also creating executable in /home/ttylec/.virtualenvs/tmp-195183325368ab1e/bin/python
    Installing setuptools, pkg_resources, pip, wheel...done.
    This is a temporary environment. It will be deleted when you run 'deactivate'.
    (tmp-195183325368ab1e) ➜  tmp-195183325368ab1e python --version
    Python 3.6.8
    (tmp-195183325368ab1e) ➜  tmp-195183325368ab1e pip install pyan3
    Collecting pyan3
      Using cached https://files.pythonhosted.org/packages/1a/82/d1b47fbcde2472d5954b4ed70cc3acf67d27bb0e83cf9b5cd5785684c629/pyan3-1.0.4-py3-none-any.whl
    Installing collected packages: pyan3
    Successfully installed pyan3-1.0.4
    (tmp-195183325368ab1e) ➜  tmp-195183325368ab1e pyan3
    Traceback (most recent call last):
      File "/home/ttylec/.virtualenvs/tmp-195183325368ab1e/bin/pyan3", line 7, in <module>
        from pyan import main
    ModuleNotFoundError: No module named 'pyan'
    

    Installing from within cloned repo works.

    bug 
    opened by ttylec 4
  • What is

    What is "dot"?

    New to Python and Graphviz, sorry!

    I stumbled on the answer by typing

    dot --help
    

    The docs should mention the prerequisite:

    sudo apt install graphviz
    
    opened by martinhbramwell 0
  • Would like to generate call graph for a very basic file

    Would like to generate call graph for a very basic file

    I'd like to generate a call graph for the following minimum working example:

    def g(x):
        return x+2
    
    def h(x):
        return x*7
    
    def f(x):
        r = g(x)
        s = h(r)
        return s
    
    if __name__=="__main__":
        print(f(3))
    

    I tried the following command:

    pyan3 test.py --dot

    But I got an error:

    TypeError: init() got multiple values for argument 'root'

    What am I doing wrong here?

    opened by amine-aboufirass 1
  • Is the project still maintained?

    Is the project still maintained?

    Thanks @Technologicat for this project, it's so useful and lightweight ! The latest commit happened a while ago, and 3 PRs have been waiting for a while. Is it still maintained? Or are you looking for a new maintainer?

    discussion 
    opened by aurelg 4
  • FileNotFoundError: [Errno 2] No such file or directory: ''

    FileNotFoundError: [Errno 2] No such file or directory: ''

    Hi,

    Recently I installed pyan and try to use it to generate a graph of my python script. Unfortunately I encountered an error. Here is my installation command and my python is 3.8.0:

    pip install git+https://github.com/Technologicat/pyan.git
    

    While I run the command for my own script:

    pyan3 tre_graph.py --uses --no-defines --colored --grouped --annotated --dot > tre.dot
    

    It didn't work as expected but give an error as below:

    Traceback (most recent call last):
      File "/home/wangjie/miniconda3/envs/straglr/bin/pyan3", line 8, in <module>
        sys.exit(main())
      File "/home/wangjie/miniconda3/envs/straglr/lib/python3.8/site-packages/pyan/main.py", line 208, in main
        v = CallGraphVisitor(filenames, logger=logger, root=root)
      File "/home/wangjie/miniconda3/envs/straglr/lib/python3.8/site-packages/pyan/analyzer.py", line 60, in __init__
        mod_name = get_module_name(filename)
      File "/home/wangjie/miniconda3/envs/straglr/lib/python3.8/site-packages/pyan/anutils.py", line 41, in get_module_name
        print(os.listdir(potential_root))
    FileNotFoundError: [Errno 2] No such file or directory: ''
    

    After some simple inspections of these codes that raising errors, I guess it is the problem of --root parameter. But it is inferred by default so I don't know how to fix it. Could you give some suggestions?

    Thanks!

    JieWang

    opened by Jesson-mark 2
  • Fixed anutils.get_module_name

    Fixed anutils.get_module_name

    Before this commit, I would get the following error:

    Traceback (most recent call last):
      File "/home/sam/.local/share/virtualenvs/.repos-OcsR-W1w/bin/pyan3", line 33, in <module>
        sys.exit(load_entry_point('pyan3', 'console_scripts', 'pyan3')())
      File "/home/sam/box/charmonium.cache/benchmark/.repos/pyan/pyan/main.py", line 206, in main
        v = CallGraphVisitor(filenames, logger=logger, root=root)
      File "/home/sam/box/charmonium.cache/benchmark/.repos/pyan/pyan/analyzer.py", line 60, in __init__
        mod_name = get_module_name(filename)
      File "/home/sam/box/charmonium.cache/benchmark/.repos/pyan/pyan/anutils.py", line 43, in get_module_name
        is_root = any([f == "__init__.py" for f in os.listdir(potential_root)])
    FileNotFoundError: [Errno 2] No such file or directory: ''
    

    because directories[0][0] was:

    ./pudl/src/pudl/cli.py None
    ./pudl/src/pudl
    ./pudl/src
    ./pudl
    .
    

    After this commit, the code works as expected, because the loop stops when it finds the root.

    opened by charmoniumQ 0
Releases(v1.2.0)
  • v1.2.0(Feb 11, 2021)

    Starting with this release, Pyan is now jointly maintained by @Technologicat, @jdb78, and @johnyf.

    New:

    • Sphinx extension.

    Changed:

    • Improve package root resolution.

    Fixed:

    • #62: visit_AnnAssign crash on an empty list.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Dec 10, 2020)

    This version adds HTML and SVG export by @jdb78, several small fixes by @johnyf, some individual fixes by other community members, and most importantly, brings the long-outdated PyPI package back into sync with this development repo.

    Thanks to everyone who contributed to this release!

    Source code(tar.gz)
    Source code(zip)
  • v1.0.4(Jun 25, 2019)

  • v1.0.3(Jun 25, 2019)

  • v1.0.2(Jan 3, 2018)

    Bugfix:

    • fix regression: keep wildcard if the 'resolved' target is actually an unresolved function argument

    Enhancements:

    • add --grouped-alt (-G) to make invisible defines edges to suggest grouping for GraphViz, without actually placing the nodes into GraphViz clusters. Overrides --no-defines. Overridden by --defines.
    • analyze str() and repr() if the argument is a Name or Attribute mapping to a known Node.
    • add uses edge to result from a resolved call to built-ins, important for str() and repr()
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Nov 21, 2017)

    Bugfixes:

    • crash in analyzer when resolving super() call with no known bases
    • crash in collapse_inner() during postprocessing
    • use /usr/bin/env python3 instead of hard-coded /usr/bin/python3 in hashbang in pyan.py to support virtualenvs correctly

    Enhancements:

    • analyze the with statement: add uses edges from the node containing the with block to __enter__ and __exit__ methods of the with'd object; also track binding from with ... as foo (single target only for now, and __enter__ is assumed to return self)
    • analyze instantiation: add a uses edge to MyClass.__init__ for a call to MyClass()
    • node flavoring both in analysis and in output (class, function, method, staticmethod, classmethod)
    • figure out which names correspond to arguments in FunctionDef; prevent leakage of matching names from the enclosing scope. This fixes some spurious edges.
    • avoid adding a uses wildcard when resolving super() fails. This fixes spurious, possibly seemingly recursive, uses edges in the case that part of the class hierarchy is not available for analysis. (The most common reasons for super() resolution to fail are that either the analyzer is still running pass 1 [MRO is computed between passes], or some relevant source file is not in the analyzed set.)

    Technical improvements:

    • refactor analyzer: split into the main class and anutils
    • reorder methods in the analyzer main class to make the source code more logical to read for humans
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Nov 21, 2017)

    Python 3 compatibility.

    Changes w.r.t. the long-standing version of Pyan for Python 2, https://github.com/davidfraser/pyan/commit/26faced4edcd2bbe3f0672d6b96d7fbb2099624e :

    • rewrite analyzer in Python 3, using ast and symtable
    • unlimited number of hues for output graph nodes
    • graph node hue is now based on filename, not top-level namespace
    • detailed (debug) logging with --very-verbose, can be abbreviated to -V
    • treat __init__ like any method (now shows up in the output graph)
    • add uses edges for recursive calls
    • analyze nested class definitions
    • define "self" by capturing the name of the first argument of methods and class methods, like Python does
    • analyze nested attribute accesses (e.g. self.a.b)
    • look up inherited attributes (using MRO with C3 linearization, based on static type at use site)
    • analyze super() calls
    • recognize for as a binding form to avoid name clashes between loop counters and functions defined elsewhere (however, can fail if the expression to be assigned is complex enough)
    • analyze simple item-by-item tuple assignments x,y,z = a,b,c and pythonic swap a,b = b,a
    • analyze chained assignments a = b = c
    • in analysis, use local scope for lambda, listcomp, setcomp, dictcomp, genexpr to follow Python 3 scoping rules correctly; for visualization, contract these into the parent node in postprocessing
    • yEd GraphML output support, framework for easily adding new output formats (merge PR #1 from davidfraser/pyan)
    • bugfix for unsafe graph node identifiers, fix inspired by https://github.com/davidfraser/pyan/commit/ddb62d2eef872329c5efe9ed780120eb11e11419
    • refactor code into modules for easier maintenance
    Source code(tar.gz)
    Source code(zip)
Owner
Juha Jeronen
Computational scientist with an interest in open-source development, Python, Lisp and metaprogramming.
Juha Jeronen
In-memory Graph Database and Knowledge Graph with Natural Language Interface, compatible with Pandas

CogniPy for Pandas - In-memory Graph Database and Knowledge Graph with Natural Language Interface Whats in the box Reasoning, exploration of RDF/OWL,

Cognitum Octopus 34 Dec 13, 2022
Visual Python is a GUI-based Python code generator, developed on the Jupyter Notebook environment as an extension.

Visual Python is a GUI-based Python code generator, developed on the Jupyter Notebook environment as an extension.

Visual Python 564 Jan 3, 2023
A little word cloud generator in Python

Linux macOS Windows PyPI word_cloud A little word cloud generator in Python. Read more about it on the blog post or the website. The code is tested ag

Andreas Mueller 9.2k Dec 30, 2022
A little word cloud generator in Python

Linux macOS Windows PyPI word_cloud A little word cloud generator in Python. Read more about it on the blog post or the website. The code is tested ag

Andreas Mueller 7.9k Feb 17, 2021
A Python-based non-fungible token (NFT) generator built using Samilla and Matplotlib

PyNFT A Pythonic NF (non-fungible token) generator built using Samilla and Matplotlib Use python pynft.py [amount] The intention behind this generato

Ayush Gundawar 6 Feb 7, 2022
An easy to use burndown chart generator for GitHub Project Boards.

Burndown Chart for GitHub Projects An easy to use burndown chart generator for GitHub Project Boards. Table of Contents Features Installation Assumpti

Joseph Hale 15 Dec 28, 2022
Simple CLI python app to show a stocks graph performance. Made with Matplotlib and Tiingo.

stock-graph-python Simple CLI python app to show a stocks graph performance. Made with Matplotlib and Tiingo. Tiingo API Key You will need to add your

Toby 3 May 14, 2022
A python script to visualise explain plans as a graph using graphviz

README Needs to be improved Prerequisites Need to have graphiz installed on the machine. Refer to https://graphviz.readthedocs.io/en/stable/manual.htm

Edward Mallia 1 Sep 28, 2021
Fastest Gephi's ForceAtlas2 graph layout algorithm implemented for Python and NetworkX

ForceAtlas2 for Python A port of Gephi's Force Atlas 2 layout algorithm to Python 2 and Python 3 (with a wrapper for NetworkX and igraph). This is the

Bhargav Chippada 227 Jan 5, 2023
LabGraph is a a Python-first framework used to build sophisticated research systems with real-time streaming, graph API, and parallelism.

LabGraph is a a Python-first framework used to build sophisticated research systems with real-time streaming, graph API, and parallelism.

MLH Fellowship 7 Oct 5, 2022
Automatization of BoxPlot graph usin Python MatPlotLib and Excel

BoxPlotGraphAutomation Automatization of BoxPlot graph usin Python / Excel. This file is an automation of BoxPlot-Graph using python graph library mat

EricAugustin 1 Feb 7, 2022
Generate a roam research like Network Graph view from your Notion pages.

Notion Graph View Export Notion pages to a Roam Research like graph view.

Steve Sun 214 Jan 7, 2023
PanGraphViewer -- show panenome graph in an easy way

PanGraphViewer -- show panenome graph in an easy way Table of Contents Versions and dependences Desktop-based panGraphViewer Library installation for

null 16 Dec 17, 2022
Import, visualize, and analyze SpiderFoot OSINT data in Neo4j, a graph database

SpiderFoot Neo4j Tools Import, visualize, and analyze SpiderFoot OSINT data in Neo4j, a graph database Step 1: Installation NOTE: This installs the sf

Black Lantern Security 42 Dec 26, 2022
The implementation of the paper "HIST: A Graph-based Framework for Stock Trend Forecasting via Mining Concept-Oriented Shared Information".

The HIST framework for stock trend forecasting The implementation of the paper "HIST: A Graph-based Framework for Stock Trend Forecasting via Mining C

Wentao Xu 111 Jan 3, 2023
ICS-Visualizer is an interactive Industrial Control Systems (ICS) network graph that contains up-to-date ICS metadata

ICS-Visualizer is an interactive Industrial Control Systems (ICS) network graph that contains up-to-date ICS metadata (Name, company, port, user manua

QeeqBox 2 Dec 13, 2021
It's an application to calculate I from v and r. It can also plot a graph between V vs I.

Ohm-s-Law-Visualizer It's an application to calculate I from v and r using Ohm's Law. It can also plot a graph between V vs I. Story I'm doing my Unde

Sihab Sahariar 1 Nov 20, 2021
🐍PyNode Next allows you to easily create beautiful graph visualisations and animations

PyNode Next A complete rewrite of PyNode for the modern era. Up to five times faster than the original PyNode. PyNode Next allows you to easily create

ehne 3 Feb 12, 2022
A Graph Learning library for Humans

A Graph Learning library for Humans These novel algorithms include but are not limited to: A graph construction and graph searching class can be found

Richard Tjörnhammar 1 Feb 8, 2022