Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to perform type checking with the typing Python module?

Tags:

python

typing

I am reading the typing module code and also looking into mypy to understand how it does type checking. Unfortunately for me, mypy builds a very smart tree with typed expressions that I still don't understand, and it's all based on static analysis.

I would like to implement a type check system that is dynamic (no static analysis) in Python. Assuming the function that performs type checks is called check_type, I want to accomplish the following:

>>> import typing
>>>
>>> check_type(1, int)
True
>>> check_type(1, float)
False
>>> check_type([1], typing.List[int])
True
>>> check_type([1], typing.List[float])
False
>>> check_type([1], typing.List[typing.Any])
True
>>> check_type((1,), typing.Tuple[int])
True

I thought about recreating the object type from its value, such as:

>>> get_type([1])
typing.List<~T>[int]

But this doesn't work with issubclass:

>>> issubclass(typing.List[int], typing.List[typing.Any])
False

I don't see a simple way to check types in Python without assuming a lot of things about the internals of the typing stdlib module (e.g., accessing __args__ or __tuple_params__).

How can I properly implement a check_type function that work for the cases previously listed? I am using Python 2.7.

like image 733
Hugo Tavares Avatar asked Jun 22 '16 16:06

Hugo Tavares


1 Answers

You can easily get the very limited functionality that works correctly for the simple examples provided in your question:

import mypy.api

def check_type(value, typ):
    program_text = 'from typing import *; v: {} = {}'.format(typ, repr(value))
    normal_report, error_report, exit_code = mypy.api.run(['-c', program_text])
    return exit_code == 0

int_ = 1
str_ = 'a'
list_str_ = ['a']
list_int_ = [1]
tuple_int_ = (1,)

assert check_type(int_, 'int')
assert not check_type(str_, 'int')
assert check_type(list_int_, 'List[int]')
assert not check_type(list_str_, 'List[int]')
assert check_type(list_int_, 'List[Any]')
assert check_type(tuple_int_, 'Tuple[int]')

You can even do some more advanced stuff (for example, refer to the types that correspond to classes you defined in your program) by extending this code a bit, so that mypy gets to parse your entire source code as opposed to just the current line.

Alternatively, you might want to look at enforce or typeguard.

like image 64
max Avatar answered Nov 15 '22 14:11

max