Linting#
Some approaches allow you to specify and check the validity of the code before executing it.
Annotations#
Python allows you to annotate types of varibles. By default, annotations don’t influence the program; they are just hints for static code checkers, such as linters.
Check more at the Annotations page.
The following cell shows the really basics of the annotations syntax.
val: int
lst: list[int]
def function(arg: int, arg2: str) -> int:
return 5
Here:
val
: is just a variable annotated as anint
.lst
: is a list of integers, such kind of type called “generic”. Feature is thatlist
parameterized withint
.function
: specifies the types of the arguments and has an output of typeint
.
Tools#
There is the set of tools that designed to organize the process of annotations verification:
mypy: static type checking for python.
pyright: static type checking for python.
typeguard: runtime type checking.
flake8: code style chcker.
For more details, check Tools page.
Mypy#
Tool that allows you to check if the programme respects the specified type hints.
So in the following example a function is defined that takes two arguments and they are annotated as int
.
%%writefile /tmp/mypy_example.py
def bin_sum(a: int, b: int):
return a+b
print(bin_sum("a", "b"))
Writing /tmp/mypy_example.py
The following code shows shows how to apply mypy
to this file.
!python3 -m mypy /tmp/mypy_example.py
/tmp/mypy_example.py:4: error: Argument 1 to "bin_sum" has incompatible type "str"; expected "int" [arg-type]
/tmp/mypy_example.py:4: error: Argument 2 to "bin_sum" has incompatible type "str"; expected "int" [arg-type]
Found 2 errors in 1 file (checked 1 source file)
As a result, we got corresponding errors.
Typeguard#
Type guard checks whether the value matches to the annotated types at runtime. With this library you can:
Write code that checks if the value matches to specified type - use the
typeguard.check_type()
function.Modify the behavior of the functions using the
@typeguard.typechecked
decorator - so that any inconsistency in the input/output of the function will result in an error.
The following cell checks if the literal “hello” matches to the int
annotation, and shows what kind of error typeguard
will generate in such a case.
import typeguard
try: typeguard.check_type("hello", int)
except Exception as e: print(type(e), e)
<class 'typeguard.TypeCheckError'> str is not an instance of int
The following cell saves to file code that uses the @typeguard.typechecked
decorator, as it doesn’t work in jupyter notebook.
%%writefile /tmp/typechecked_decorator.py
import typeguard
@typeguard.typechecked
def value() -> int:
return "value"
Overwriting /tmp/typechecked_decorator.py
Function returns “value” but int
is annotated. The following cell shows what kind of error typeguard
will produce for such a case.
from typechecked_decorator import value
try: value()
except Exception as e: print(type(e), e)
<class 'typeguard.TypeCheckError'> the return value (str) is not an instance of int