I tried mypy [1] before but it was a bit cumbersome to keep it checking my code. At work I use pytype [2]. It's good enough but that's only because someone else made a build system integration for me. Pyre's scan-all-the-files approach seems easier to get started. Is there any catch? Which one are you using and what's your impression?
[1] https://mypy.readthedocs.io/en/stable/
[2] https://github.com/google/pytypePyright's VSCode integration, Pylance, provides a great auto complete experience. So I use Pyright for autocomplete in VSCode and mypy for type checking.
Worse, importing third party packages often fails silently and when you can get error messages they tend to be completely inactionable (I recall one error message which linked to a web page that had lots of details and workarounds for fixing other problems, but none of which solved the error itself).
Figuring out how to distribute my own type annotations was similarly painful. IIRC, you have to drop a specially-named file into a particular directory and this is all undocumented save for a dense PEP and the error messages are unsurprisingly terrible. All of these things are actionable, but the progress seems slow (these have been among my top grievances since the project debuted, so the maintainers and I have different priorities, clearly).
The problems for which I'm less optimistic tend to revolve around shoehorning typing into existing Python syntax--e.g., to get a callback that takes kwargs you have to define a protocol with a `__call__` method that takes kwargs because you can't express it with `typing.Callable`. Similarly where a language with first-class support for types might have `type Foo<T>`, Python makes you write `T = TypeVar("T"); class Foo(Generic[T])` or something like that, and it gets more confusing when you only want one of the methods to be generic and I can never remember whether that `T` takes on a single type across all uses or which scope I need to define it in, etc. This is largely an ergonomic nightmare and I don't have lots of optimism for this stuff to improve unless the Python community really comes to embrace typing as the default way to use Python (but I suspect most people who care a lot about this kind of stuff will leave for Go or other languages where these things just work out of the box).
Lack of recursive types has been a major deal breaker for me. If you have a class Foo that can construct a class Bar, and a class Bar that can construct a class Foo, you can't express that in mypy without Any-Generics.
To me, at this point, mypy is barely a linter, it's more of a "this helps my IDE autocomplete faster", and definitely not a type system.
from __future__ import annotations
class X:
def __init__(self, value: int) -> None:
self.value = value
def to_y(self) -> Y:
return Y(self.value)
class Y:
def __init__(self, value: int) -> None:
self.value = value
def to_x(self) -> X:
return X(self.value)
x = X(10).to_y().to_x()
print(x.value)And by "successfully" I mean "it ran at all". Every other thing I've thrown at it has caused it to crash. I quite like the concept, but implementation has been rather abysmal as far as I've seen. Has it improved in ~ the past year?
I don't know about you but I find PEP 484 very clear here: https://www.python.org/dev/peps/pep-0484/#scoping-rules-for-...
The nice thing is that, since TypeVars are ordinary variables, you can re-use them / import them in multiple modules and avoid a lot of boilerplate code.
Maybe I'm missing something, but the boilerplate only exists because Python makes you define them as ordinary variables in the first place. So while you can have a `foo.py` file like this:
T = TypeVar("T")
And a `bar.py` file like this: from foo import T
class Bar(Generic[T]):
...
So are you saying that this is less boilerplate than a `bar.py` that just defines its own `T` TypeVar? Because that seems like a pretty comparable amount of boilerplate. Or are you saying that it's less boilerplate than languages that don't treat TypeVars as ordinary variables, e.g., Rust? Because in Rust our `bar.rs` file would look like this: `struct Bar<T> {...}` (and the scoping rules are patently obvious, to boot).I'm planning to migrate this to my own blog soon.
You might be interested in the discussion over here then -> https://github.com/python/typing/issues/769#issuecomment-741...
Or does it mean that we should check types using all type-checkers available to have the most compliant code possible?
I think for most people any of the 4 big ones is fine. Most of the common type errors will look identical regardless of which you pick. Configuring multiple in CI is pretty straightforward if you want to go full. My current codebase has mypy + pyright configured. Pyright was a mix of fast response time on github issues + I use vscode and was the one that added type checks to CI.
If you want a deep dive pycon is this week I think and there's a day for type checking related talks including one talk comparing the 4. I think type checking day is thursday.
Hope they post the recordings somewhere later.
It does seems to support the entire-directory parsing as well. That's nice! Let me give it a try next time. Thanks for the tip!
As a reminder to myself, here is the link to the doc: https://google.github.io/pytype/