How can I get format to not cause a type-hinting error?

Pro Q

I have the following list comprehensions in Python:

from typing import cast

# everything is fine
print([value for value in [1, 2, 3, 4]])

# on the first "value": Expression type contains "Any" (has type "List[Any]")
print("{}".format([value for value in [1, 2, 3, 4]]))

# on the "cast": Expression type contains "Any" (has type "List[Any]")
print("{}".format([cast(int, value) for value in [1, 2, 3, 4]]))

Why does using format cause Mypy to give me back errors? As you can see, I tried to use casting and it still failed.

This question looks similar, but my particular case is weird because Mypy seems to be fine as long as I'm not using the format function (yet it's always okay with the print function).

Is there anything I can do to not have the lines with formatting give me errors? (Or should I just # type: ignore them?)

EDIT: Note that this does not appear to just be an issue with my Atom linter. I'm using Mypy version 0.701 and I ran Mypy on the file with the following result:

$ python3 -m mypy testing_list_iter.py --disallow-any-expr
testing_list_iter.py:7: error: Expression type contains "Any" (has type "List[Any]")
testing_list_iter.py:10: error: Expression type contains "Any" (has type "List[Any]")
Michael0x2a

This actually has nothing to do with list comprehensions: this is actually a bad interaction between the type signature for str.format(...), how mypy performs type inference, and the --disallow-any-expr flag.

Here's the type signature for str.format(...), pulled from typeshed:

def format(self, *args: Any, **kwargs: Any) -> str: ...

When mypy performs type inference on function calls, it'll attempt to use the declared parameter types to help provide context for the expressions you pass in.

So in this case, since the arguments are all Any here, mypy will realize that it can shortcut a lot of the type inference it usually needs to do. So, if we pass in any list literal into str.format(...), mypy will just decide "hey, the inferred type can be just List[Any]".

Here's a sample program that demonstrates this behavior (when checked with the --disallow-any-expr flag):

from typing import cast, Any

def test1(x: Any) -> None:
    pass

def test2(x: object) -> None:
    pass

# Revealed type is 'builtins.list[Any]'
# Expression type contains "Any" (has type "List[Any]")
test1(reveal_type([1, 2, 3, 4]))

# Revealed type is 'builtins.list[builtins.int*]'
test2(reveal_type([1, 2, 3, 4]))

Note that when we try using a function that accepts object instead of Any, mypy will infer the full type instead of doing this shortcut. (Mypy could technically do the same kind of shortcut, since all types also subclass object, but I suspect it was just simpler implementation-wise not to -- unlike Any, object is just a regular plain-old type so special-casing interactions with it is kind of weird.)

Normally, it doesn't matter too much how exactly mypy handles this case: you get accurate results either way.

However, the --disallow-any-expr flag is still pretty new and relatively untested (it's too aggressive for a lot of people, especially those who are trying to use mypy on existing codebases), so we get these bad interactions from time to time.


So, what's the fix?

The best possible fix would be for you to contribute a pull request to Typeshed modifying str.format(...) and unicode.format(...) in the builtins.pyi file so they accept objects instead of Any.

This change would be in line with Typeshed's contribution guidelines anyways -- specifically, this snippet in the middle of the "Conventions" section:

When adding type hints, avoid using the Any type when possible. Reserve the use of Any for when:

  • the correct type cannot be expressed in the current type system; and
  • to avoid Union returns (see above).

Note that Any is not the correct type to use if you want to indicate that some function can accept literally anything: in those cases use object instead.

Then, you wait for the next release of mypy, which theoretically ought to be soon-ish.

In the meantime, what you can do is just assign the results of your list comprehension to a new variable, then pass that into str.format(...):

results = [value for value in [1, 2, 3, 4]]
print("{}".format(results))

This will cause mypy to infer the type of your list comprehension without the Any context, causing it to infer the full-fledged type. This sidesteps the bad interaction with the --disallow-any-expr flag.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How can I fix This error and what is the cause of it?

In python type-hinting, how can I make an argument accept any subclass of a base class?

How can I extend class parameters with a method while preserving type hinting in typescript?

In PHPStorm, how can I make type hinting work when I have a superclass method that returns a different type from each subclass

How can I get rid off this Error Message which cause block any update to OS

PyCharm Professional - type hinting error

How do I use Type Hinting to show a List<Foo>

How do I return type hinting defined types

How can I get a @PostAuthorize failure to cause a rollback with @Transactional?

How can I get the type of a Type?

How can I put Date type parameter as a String in GET request? Format "yyyy-MM-dd"

How can I get summary in scientific format

How can I get actual date in this format?

How can I get the token in JSON format

through parameter determine subclass type , but get error " Use of undeclared type ". How can I do?

How can format specifiers cause a buffer overflow?

How to fix mypy error, "Expression has type Any [misc]", for python type hinting of int __pow__ int?

How to define an alias for a type in Python for type hinting

How to add type hinting to "class" type in python

Implement type hinting 'parent' in interface throws an error

Python 3.5 type hinting does not result in an error

Can php have a mixed type hinting?

I need to include two header files to each other not using forward declaration cause get "incomplete type" error

How can I trigger a type error in Haskell?

How can i solve this type of mysql error

How can I get a tag type with a MutationObserver?

How can I get custom type with reflect?

How can I get a string as a Type object?

How can I get the file type of a download?