Search code examples
python-3.xpylintmypytypecheckingstatic-code-analysis

Type checking tool for Python 3


I am trying to run a command that gives some aggregated information on type checking, static code analysis, etc. in some Python source code provided as a directory. If such thing exists, then I would like to add it to a Makefile invoked during some CI pipelines to validate a code base.

I've created this dummy source code file with a runtime issue

File foo_sample.py

def foo_func(my_num):
    return 1 + my_num


def bar_func():
    foo_func("foo")


if __name__ == "__main__":
    bar_func()

It throws this runtime error:

TypeError: unsupported operand type(s) for +: 'int' and 'str'.

Now I've tried to detect this type error with various tools, but they all fail to find these kind of problems. See the commands in the following list:

  • pyflakes foo_sample.py,
  • flake8 foo_sample.py,
  • pylint foo_sample.py,
  • mypy --check-untyped-defs foo_sample.py,
  • prospector --strictness veryhigh foo_sample.py

I know I could detect these issues with unittest, but the code base is quite large and untested to some degree. We frequently see runtime errors and address them with a unit test or an integration test. However, we would like to detect them during the execution of a CI pipeline.

Is there a way to run these kind of checks before running the code itself?

How can I avoid to discover these errors at runtime?


Solution

  • I found pytype useful in this scenario.

    When invoking pytype broken_code.py on this code:

    def foo_func(my_num):
        return 1 + my_num
    
    
    def bar_func():
        foo_func("foo")
    
    def run_func(my_func):
        my_func()
    
    
    if __name__ == "__main__":
        bar_func()
        run_func(bar_func())
    

    I correctly find in the output:

    • line 3, in foo_func: unsupported operand type(s) for +: 'int' and 'str' [unsupported-operands]
    • line 10, in run_func: 'NoneType' object is not callable [not-callable]

    The command exits with an error so a Makefile invoking it could block the execution of a pipeline in a CI environment.

    Also, those error checks like [unsupported-operands], etc. can be enabled or disabled with comments in the code, e.g.,

    • first disable the checks # pytype: disable=attribute-error
    • then enable the checks again # pytype: enable=attribute-error

    See how to use these comments in the documentation, Error classes.