/
MyPy

MyPy

Python 3.6 allows you to annotate your code with the type of variable you are declaring or are expecting to be passed/returned by a function. This doesn't do any runtime checking but is instead intended for use by code checking tools, one of which is mypy.

Mypy can be installed by -

pip install mypy

and run using

mypy --ignore-missing --check my_piece_of_code.py

The reason for the ignore missing parameter is that MyPy only attemps to analyse code in your local directory. If you are refrencing modules you have installed then MyPy expectes there to be a Type Stub for the package which explains how the types that are defined in the package relate to the Python primative types. These stubs exist for some libraries but not many, although the standard library is pretty well covered.


You may then get some output like -

$ mypy --ignore-missing-imports --check ukrdc/services/rda_to_pv/process.py
ukrdc\services\rda_to_pv\process.py:13: error: Need type annotation for 'test_dict'

What this is saying is that the code is defining the variable test_dict but you haven't added the annotations to precicely define the type.

https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html

Is a good resource for working out what you should put.

In this case we go from

test_dict = dict()

to

test_dict: Dict[str, list] = dict()

so it knows I expect the key will be a string and the value will be a list.

I then ran it again and got some errors about how I was assigning Tuples and not Lists. Not an actual problem but at least it shows its working.

I then tried running it on various parts of the UKRDC and didn't find any issues. My suspicion is that this is because almost all of the data comes from external sources (Pyxb, lxml etc.) and without the Type Stubs it doesn't know what type it will be.

The only interesting bit I found was -

$ mypy --ignore-missing-imports --check ukrdc/services/pv_rda_extract/process.py
ukrdc\services\pv_rda_extract\adapters.py:52: error: Item "None" of "Optional[Match[Any]]" has no attribute "group"

This relates to:

def num(self):
    """Extract and return number from question type code."""
    return int(re.search('([0-9]+)', self.question.questiontypecode).group())

and is saying that re.search could return None which wouldn't have the .group() attribute. Again, may not be an actual problem but shows it works.

Finally I tried running it on the main scripts for Validation/Editor. Note that Validation uses the future-fstrings module and you will need to install this for Python 3.6 before MyPy can read the code.

Here we get a load of actual errors such as -

scripts\RR_database_editor.py:2684: error: Unsupported operand types for < ("datetime" and "str")
scripts\RR_database_editor.py:2685: error: "str" has no attribute "timetuple"
scripts\RR_database_editor.py:2686: error: Incompatible types in assignment (expression has type "datetime", variable has type "str")
scripts\RR_database_editor.py:2687: error: Argument 1 to "strftime" of "datetime" has incompatible type "str"; expected "datetime"

Which are all caused by the same variable being a text representation of a date and not a date. Luckily this isn't an important feature but it won't be working correctly as it is.