1

I'm trying to write unit tests for types we're using with beartype, our runtime type checker. The tests run as expected, however MyPy will not accept the code.

The following code works, however the MyPy check fails.

def typecheck(val: Any, t: type):
    """
    isinstance() does not allow things like Tuple[Int]
    """

    @beartype
    def f(v: t):
        return v

    try:
        f(val)
    except BeartypeCallHintPepParamException:
        return False
    return True

# passes
def test_typecheck():
    assert typecheck((1,), Tuple[int])
    assert not typecheck((1,), Tuple[str])

However, I get the following error. The linked to page isn't helpful.

error: Variable "t" is not valid as a type
note: See https://mypy.readthedocs.io/en/latest/common_issues.html#variables-vs-type-aliases

How do I properly annotate this? Ive tried TypeVars but I get the same error.

Eric Yabs
  • 11
  • 3
  • 1
    Function annotations aren't values; you can't do this, at least not without using `exec` (which `mypy` probably can't deal with anyway). – chepner Jul 21 '21 at 18:49
  • 1
    `mypy` does *static* type checking; `f` does not exist until you actually execute the code. – chepner Jul 21 '21 at 18:50
  • Maybe `T = TypeVar('T'); def typecheck(..., t: Type[T]): ... def f(v: T)`? – chepner Jul 21 '21 at 18:54
  • @chepner This passes MyPy but causes the unit tests to fail. Presumably since the passed param `t` no longer being used as the type. – Eric Yabs Jul 21 '21 at 19:15
  • You can't use `t` as a type hint at all. The purpose of the type var `T` is to parameterize the type hint for `t`. `Type[T]` indicates that `t` is some type, rather than value of type `T`, so that later `def f(v: T)` indicates that `v` has whatever type was passed as `t`. – chepner Jul 21 '21 at 19:17
  • But I do see what the issue is. – chepner Jul 21 '21 at 19:20
  • What about assigning the type hint explicitly, rather than using function annotations? `f.__annotations__['x'] = t`? (Wrote this up as an answer; I'll delete if it turns out not to work.) – chepner Jul 21 '21 at 19:36

1 Answers1

1

Assign the type hint directly, rather than letting it be assigned via a function annotation.

def typecheck(val, t):
    """
    isinstance() does not allow things like Tuple[Int]
    """

    @beartype
    def f(v):
        return v
    f.__annotations__['v'] = t

    try:
        f(val)
    except BeartypeCallHintPepParamException:
        return False
    return True

# passes
def test_typecheck():
    assert typecheck((1,), Tuple[int])
    assert not typecheck((1,), Tuple[str])
chepner
  • 497,756
  • 71
  • 530
  • 681