2

Is there a way (preferably using the ast module) to know if a function has a required number of arguments?

For example, if a user interface allows a user to insert a python expression for example "sum(x)" but the user has mistakenly typed "sum()" is there a way to validate that expression before runtime?

I have called ast.dump on every node in the symbol tree but the information on these symbols seems insufficient for this kind of analysis?

For example:

#own debug code added to ast.py
def visit(self, node):
  print(dump(node),True, False)
  method = 'visit_' + node.__class__.__name__
  visitor = getattr(self, method, self.generic_visit)
  return visitor(node)  

yields:

'Module(body=[Expr(value=Call(func=Attribute(value=Name(id='Math', ctx=Load()),
 attr='cos', ctx=Load()), args=[Num(n=0.5)], 
 keywords=[], starargs=None, kwargs=None))])'

Which doesn't really differ from a function like print() which does not require a specific number of arguments.

Willeman
  • 720
  • 10
  • 24
  • 2
    You'd have to resolve the object being called and analyse *that*. Python doesn't know this either *until you actually execute the call*. – Martijn Pieters Sep 26 '14 at 15:03
  • How do you define "required argument" for a Python function? Where is this defined? –  Sep 26 '14 at 15:03
  • 2
    I'd refrain from naming your module `ast.py`. – roippi Sep 26 '14 at 15:04
  • @Tichodroma: positional arguments on the callable object, presumably. But the AST of the *call expression* won't show this because that isn't known until you actually run the code. – Martijn Pieters Sep 26 '14 at 15:09
  • @Tichodroma I'm trying to think of a way to pre-empt 'TypeError: sum expected at least 1 arguments, got 0' at runtime. I'm actually not sure how this is defined for the sum() built-in function – Willeman Sep 26 '14 at 15:12
  • @MartijnPieters thanks. point taken. – Willeman Sep 26 '14 at 15:14
  • @Willeman: for C-defined (built-in) functions you cannot introspect this at all. – Martijn Pieters Sep 26 '14 at 15:46
  • @Willeman: hrm, I was under the impression this was for Python 2; for Python 3.4 and up a portion (but not all) built-in objects now have introspectable signatures (usable with `inspect.signature()`). `sum()` and `math.cos()` are not among them. I expect future Python versions to remedy this. – Martijn Pieters Sep 26 '14 at 17:35

1 Answers1

1

You cannot see from a call expression what arguments the callable expects. Python leaves this entirely to the callable at runtime.

For static code analysis your only option is to resolve the callable (hoping that it is not too dynamic in nature, e.g. will change at the runtime), and for C-defined objects have your own database of signatures. This is the route the Komodo CodeIntel library takes (OSS, used in other projects such as SublimeCodeIntel). C-based extensions are supported with CIX files, which essentially contain callable signatures.

At runtime, you can use inspect.signature() to introspect call signatures. C functions are only partially supported at the moment, only those that use the Argument Clinic have signature info stored, see What are __signature__ and __text_signature__ used for in Python 3.4

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343