Is there any feature I can turn on to require that an entire file is statically typed?
Or in general, what sort of tools would you use to enforce good mypy habits in a large project?
cat file.py | sed 's/^\(\s*def.*)\):/\1 -> None/
Having a flag that actually causes mypy to throw an error if it encounters something that isn't type'd would be potentially useful, actually.
Here's what Facebook did with HHVM: http://docs.hhvm.com/manual/en/hack.modes.strict.php
A strict mode has actually been on my own to-do list since somewhere around 2013, but I never created an issue for it.
Something like this could do the trick:
# mypy: strict
def f(x: int): # Error: Return type missing and defaults to 'Any'
...
This would be especially useful if/when we are going to use a 'weak' type checking mode by default for module top levels. It wouldn't complain about things like this:
x = [] # Error in strict mode but okay in weak mode
I would love to have this feature. Where would be a place to start? I'm completely unfamiliar with Mypy (but I am with Python).
The following is an example of what I would like to be warned on.
Here is correct code with type annotations:
def greeting() -> List[str]:
return ["zapu"]
def main() -> None:
print("Hello", ', '.join(greeting()))
Here is code that will fail type-check (and rightfully so):
def greeting() -> List[int]:
return [1]
def main() -> None:
print("Hello", ', '.join(greeting()))
output:
test.py: note: In function "main":
test.py:28: error: Argument 1 to "join" of "str" has incompatible type List[int]; expected Iterable[str]
Here is code that passes type-check but fails at runtime:
def greeting():
return [1]
def main() -> None:
print("Hello", ', '.join(greeting()))
output:
Traceback (most recent call last):
File "test.py", line 32, in <module>
main()
File "test.py", line 28, in main
print("Hello", ', '.join(greeting()))
TypeError: sequence item 0: expected str instance, int found
I am unsure what's the correct approach here, but consider that this could be avoided if type annotations were contagious. That is, every function that is type-annotated can only call type-annotated functions. So even if greeting() was in some other module, it would keep failing to type-check until I make a stub for it.
That sounds like the right approach to me. I realized that that shouldn't be too hard to implement, so I took a stab at it above. With #1230 (and mypy --strict test.py), here's what I get for your last example:
def greeting():
return [1]
def main() -> None:
print("Hello", ', '.join(greeting()))
test.py: note: In function "main":
test.py:5: error: call to untyped function "greeting" in typed context
Wow, thanks! I'll take a look later in the day.
This functionality is now available under the flag --disallow-untyped-calls.
Cool!
Most helpful comment
This functionality is now available under the flag
--disallow-untyped-calls.