Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mypy "invalid type" error

Tags:

python

mypy

I'm trying to implement type annotations in a current project, and am receiving errors from mypy that I don't understand.

I'm using Python 2.7.11, and newly installed mypy in my base virtualenv. The following program runs fine:

from __future__ import print_function
from types import StringTypes
from typing import List, Union, Callable

def f(value):     # type: (StringTypes) -> StringTypes
    return value

if __name__ == '__main__':
    print("{}".format(f('some text')))
    print("{}".format(f(u'some unicode text')))

But running mypy --py2 -s mypy_issue.py returns the following:

mypy_issue.py: note: In function "f":
mypy_issue.py:8: error: Invalid type "types.StringTypes"

The above types appear to be in Typeshed... the mypy documentation says "Mypy incorporates the typeshed project, which contains library stubs for the Python builtins and the standard library. "... Not sure what "incorporates" means - do I need to do something to "activate", or provide a path to, Typeshed? Do I need to download and install(?) Typeshed locally?

like image 900
James Haskell Avatar asked Aug 08 '16 18:08

James Haskell


1 Answers

The problem is that types.StringTypes is defined to be a sequence of types -- the formal type signature on Typeshed is:

StringTypes = (StringType, UnicodeType)

This corresponds to the official documentation, which states that the StringTypes constant is "a sequence containing StringType and UnicodeType"...

So then, this explains the error you're getting -- StringTypes isn't an actual class (it's probably a tuple) and so mypy doesn't recognize it as a valid type.

There are several possible fixes for this.

The first way would probably be to use typing.AnyStr which is defined as AnyStr = TypeVar('AnyStr', bytes, unicode). Although AnyStr is included within the typing module, it is, unfortunately, somewhat poorly documented as of now -- you can find more detailed information about what it does within the mypy docs.

A slightly less cleaner way of expression this would be to do:

from types import StringType, UnicodeType
from typing import Union

MyStringTypes = Union[StringType, UnicodeType]

def f(value):     
    # type: (MyStringTypes) -> MyStringTypes
    return value

This also works, but is less desirable because the return type is no longer obligated to be the same thing as the input type which is usually not what you want when working with different kinds of strings.

And as for typeshed -- it's bundled by default when you install mypy. In an ideal world, you shouldn't need to worry about typeshed at all, but since mypy is in beta and so typeshed is being frequently updated to account for missing modules or incorrect type annotations, it might be worth installing mypy directly from the Github repo and installing typeshed locally if you find yourself frequently running into bugs with typeshed.

like image 196
Michael0x2a Avatar answered Sep 17 '22 04:09

Michael0x2a