Technologicat / pyan

Static call graph generator. The official Python 3 version. Development repo.
GNU General Public License v2.0
323 stars 56 forks source link

IndexError in visit_AnnAssign #62

Closed njordr closed 3 years ago

njordr commented 3 years ago

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

Technologicat commented 3 years ago

Hi,

Hmm. Let's see if we can figure this out just by looking at the analyzer code. Since it's running the first branch of the if, at least we know that node.value is not None. Then, value = sanitize_exprs(node.value); that's a Pyan internal function, whose result should be a tuple.

It seems that for some reason, sanitize_exprs is returning an empty tuple for this particular input.

To debug further, could you modify your copy of analyzer.py, replacing the visit_AnnAssign method with the version below (there's just one added print), and then post the last thing it printed when it crashes?

    def visit_AnnAssign(self, node):  # PEP 526, Python 3.6+
        target = sanitize_exprs(node.target)
        self.last_value = None
        if node.value is not None:
            value = sanitize_exprs(node.value)
            print(id(node), value, ast.dump(node.value))  # <--- added this print here
            self.logger.debug("AnnAssign %s %s, %s:%s" % (get_ast_node_name(target[0]),
                                                          get_ast_node_name(value[0]),
                                                          self.filename, node.lineno))
            self.analyze_binding(target, value)
        else:  # just a type declaration
            self.logger.debug("AnnAssign %s <no value>, %s:%s" % (get_ast_node_name(target[0]),
                                                                  self.filename, node.lineno))
            self.last_value = None
            self.visit(target[0])
        # TODO: use the type annotation from node.annotation?
        # http://greentreesnakes.readthedocs.io/en/latest/nodes.html#AnnAssign
njordr commented 3 years ago

These the values returned:

140309596494816
[]
List(elts=[], ctx=Load())
Technologicat commented 3 years ago

Thanks! Now I see the problem. node.value is an empty list, so it obviously has no elements.

Since the code triggering the error is just a debug log call, I think it's safe to change the value[0] to just value. It'll sometimes produce a bit more stuff in the debug log, but that should be fine.

Could you try that and report back if it works? If so, I'll push a fix.

njordr commented 3 years ago

It works without the index, thanks

Technologicat commented 3 years ago

Thanks for testing! I'll push a fix.