python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.3k stars 2.8k forks source link

Runtime check against underlying type of NewType #3325

Open rkr-at-dbx opened 7 years ago

rkr-at-dbx commented 7 years ago

Motivation: given output from (e.g.) json or sqlite3, check that some part of it is properly typed, and wrap it in an appropriate NewType wrapper for use elsewhere.

# still in flux; may become 'float' or other type soon
Timestamp = NewType('Timestamp', int)

def _validate_timestamp(n: Any) -> Timestamp:
    if isinstance(n, ???):  # ???
        return Timestamp(n)
    else:
        raise TypeError(f"invalid alleged Timestamp: {n}")

At present there seems to be no documented way to do the isinstance check, save to substitute int directly. This will be incorrect if Timestamp's underlying implementation type changes; should it change to float, mypy will not warn that _validate_timestamp needs to be updated.

As a workaround, one can currently rely on undocumented internals:

    if isinstance(n, Timestamp.__supertype__):  # type: ignore
gvanrossum commented 7 years ago

Maybe some undocumented internals of the typing module should be documented. Then this would be an issue for https://github.com/python/typing (or perhaps PEP 484 and https://github.com/python/cpython).

But maybe there's a quick solution: use a type alias instead of int in the NewType() call. E.g.

_Timestamp = int  # May become e.g. float
Timestamp = NewType('Timestamp', _Timestamp)