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.
[1, 2, 3, 4]output)