Python >=3.5: Checking type annotation at runtime

13,862

Solution 1

I was looking for something similar and found the library typeguard. This can automatically do runtime type checks wherever you want. Checking types directly as in the question is also supported. From the docs,

from typeguard import check_type

# Raises TypeError if there's a problem
check_type('variablename', [1234], List[int])

Solution 2

There is no such function in the typing module, and most likely there won't ever be.

Checking whether an object is an instance of a class - which only means "this object was created by the class' constructor" - is a simple matter of testing some tagging.

However, checking whether an object is an "instance" of a type is not necessarily decidable:

assert isinstance(foo, Callable[[int], str]), 'Wrong type'

Although it is easy to inspect the typing annotations of foo (assuming it's not a lambda), checking whether it complies to them is generally undecidable, by Rice's theorem.

Even with simpler types, such as List[int] the test will easily become far too inefficient to be used for anything but the smallest toy examples.

xs = set(range(10000))
xs.add("a")
xs.pop()
assert isinstance(xs, Set[int]), 'Wrong type'

The trick that allows type checker to perform this operation in a relatively efficient way, is to be conservative: the type checker tries to prove that foo always return int. If it fails, it rejects the program, even though the program may be valid, i.e. this function is likely to be rejected, although it is perfectly safe:

def foo() -> int:
    if "a".startswith("a"):
        return 1
    return "x"

Solution 3

This is what I have discovered recently, basically this decorator does type checking at runtime raising exception if some type definition did not match. It can also do type checking for nested types (dict of strings, etc)

https://github.com/FelixTheC/strongtyping

Example:

from strongtyping.strong_typing import match_typing

@match_typing
def func_a(a: str, b: int, c: list):
   ...

func_a('1', 2, [i for i in range(5)])
# >>> True

func_a(1, 2, [i for i in range(5)])
# >>> will raise a TypeMismatch Exception
Share:
13,862
Bertrand Caron
Author by

Bertrand Caron

Interets : Cocoa and Mac Application Development.

Updated on June 06, 2022

Comments

  • Bertrand Caron
    Bertrand Caron about 2 years

    Does the typing module (or any other module) exhibit an API to typecheck a variable at runtime, similar to isinstance() but understanding the type classes defined in typing?

    I'd like to be to run something akin to:

    from typing import List
    assert isinstance([1, 'bob'], List[int]), 'Wrong type'
    
  • max
    max about 7 years
    Yes. In an answer to a similar question, I came to this conclusion too (although I deleted those paragraphs because I thought my explanation was not very clear). I think the python typing / PEP 484 type system is built for static type checking and is inappropriate for dynamic type checking. A practically useful dynamic type system can be built, but it will be very different (mostly much simpler) than PEP 484. And arguably, a pretty good one is already included with your off-the-shelf python interpreter.
  • crypdick
    crypdick over 3 years
    Better yet, typeguard's @typechecked decorator lets you automatically do typehint validation on all inputs and outputs to a function. Or, if you slap it on a class definition, it'll do runtime validation on all of its methods
  • Noldorin
    Noldorin over 3 years
    "There is no such function in the typing module, and most likely there won't ever be." -- oops!
  • jcsahnwaldt Reinstate Monica
    jcsahnwaldt Reinstate Monica over 2 years
    @Elazar: Nice answer! A bit of nitpicking: I don't think Rice's theorem is enough to prove that a type system is undecidable. Deciding whether a type system is decidable isn't that easy. :-) 3fx.ch/typing-is-hard.html (I don't know if there is a well-defined type system for Python that has some kind of parametric polymorphism. If there is, chances are it's undecidable. But proving it might be a good deal of work.)
  • Elazar
    Elazar over 2 years
    @jcsahnwaldtReinstateMonica I think there are two different issues here. The question whether arbitrary code has runtime type violation is always undecidable, since it is a nontrivial property. You are talking about the existence of a sound type-checking algorithm for a system with syntactic typing rules. These rules may or may not be truing-complete.