I've been using Pyrefly and loving it compared to Pyright, but they recently shipped some updates with crash bugs that forced me to pin to a previous version, which is annoying. Unfortunately my first impression of ty isn't great either. Trying to install the ty extension on the current version of Cursor says "Can't install 'astral-sh.ty' extension because it is not compatible with the current version of Cursor (version 2.2.20, VSCode version 1.105.1)."
If I choose "install previous version" I am able to install the pre-release version from 12 hours ago without issue. Then on the extension page I get a button labeled "Switch to Release Version" and when I press it I get an error that says "Can't install release version of 'ty' extension because it has no release version." Filed a GitHub issue with these details.
In the meantime, the previous version appears to be working well! I like that it worked without any configuration. The Pyrefly extension needed a config tweak to work.
https://htmlpreview.github.io/?https://github.com/python/typ...
If that table is anything to go by, Pyright is not to be underestimated.
I have briefly tried ty (LSP) in Emacs and it seems to work well so far. The only questionable thing I've encountered is that when the signature of a method is shown, the type annotations of some parameters seem to be presented in a particularly verbose form compared to what I'm used to - maybe they're technically correct but it can be bit much to look at.
Anyway, odds are pretty good that ty is what I will end up using long-term, so thanks and congrats on releasing the first beta!
Mypy is trash. Nice to have a table to point to to prove it.
That said I'm very happy user of uv, so once Ty becomes ready enough will be happy to migrate.
And what do you use instead?
(I was on the Python Typing Council and helped put together the spec, the conformance test suite, etc)
Edit: Based on this other comment, the point was also about things not covered by the spec. “The spec mostly concerns itself with the semantics of annotations, not diagnostics or inference.” https://news.ycombinator.com/item?id=46296360
A shared spec for this is important because if you write a Python library, you don’t want to have to write a different set of types for each Python type checker
Here are some things the spec has nothing to say about:
Inference
You don’t want to annotate every expression in your program. Type checkers have a lot of leeway here and this makes a huge difference to what it feels like to use a type checker.
For instance, mypy will complain about the following, but pyright will not (because it infers the types of unannotated collections as having Any):
x = []
x.append(1)
x[0] + "oops"
The spec has nothing to say about this.Diagnostics
The spec has very little to say about what a type checker should do with all the information it has. Should it complain about unreachable code? Should it complain if you did `if foo` instead of `if foo()` because it’s always true? The line between type checker and linter is murky. Decisions here have nothing to do with “what does this annotation mean”, so are mostly out of scope from the spec.
Configuration
This makes a huge difference when adapting huge codebases to different levels of type checking. Also the defaults really matter, which can be tricky when Python type checkers serve so many different audiences.
Other things the spec doesn’t say anything about: error messages quality, editor integration, speed, long tail of UX issues, implementation of new type system features, plugins, type system extensions or special casing
And then of course there are things we would like to spec but haven’t yet!
This is incorrect. pyright will infer the type of x as list[Unknown].
PR is somewhat WIP-ish but I needed some motivation to do OSS work again :)
> At time of writing, many of the remaining rules require type inference and/or multi-file analysis, and aren't ready to be implemented in Ruff.
ty is actually a big step in this direction as it provides multi-file analysis and type inference.
(I work at Astral)
Also, it's also too bad we have three competing fast LSP/typechecker projects now We had zero 1 year ago.
I agree though. Hope this is successful and they keep building awesome open-source tools.
It's definitely a narrow path for them to tread. Feels like the best case is something like Hashicorp, great until the founders don't want to do it anymore.
As a very basic example I ran into last week, Python tooling, even the nice Astral tooling, seems to be almost completely lacking any good detection of what source changes need to trigger what rebuild steps. Unless I’ve missed something, if I make a change to a source tree that uv sync doesn’t notice, I’m stuck with uv pip install -e ., which is a wee bit disappointing and feels a bit gross. I suppose I could try to put something correct into cache-keys, but this is fundamentally wrong. The list of files in my source tree that need to trigger a refresh is something that my build system determines when it builds. Maybe there should be a way to either plumb that into uv’s cache or to tell uv that at least “uv sync” should run the designated command to (incrementally) rebuild my source tree?
(Not that I can blame uv for failing to magically exfiltrate metadata from the black box that is hatchling plus its plugins.)
It's really helpful to have examples for this, like the one you provide below (which I'll respond to!). I've been a maintainer and contributor to the PyPA standard tooling for years, and once uv "clicked" for me I didn't find myself having to leave the imperative layer (of uv add/sync/etc) at all.
> As a very basic example I ran into last week, Python tooling, even the nice Astral tooling, seems to be almost completely lacking any good detection of what source changes need to trigger what rebuild steps.
Could you say more about your setup here? By "rebuild steps" I'm inferring you mean an editable install (versus a sdist/bdist build) -- in general `uv sync` should work in that scenario, including for non-trivial things where e.g. an extension build has to be re-run. In other words, if you do `uv sync` instead of `uv pip install -e .`, that should generally work.
However, to take a step back from that: IMO the nicer way to use uv is to not run `uv sync` that much. Instead, you can generally use `uv run ...` to auto-sync and run your development tooling within an environment than includes your editable installation.
By way of example, here's what I would traditionally do:
python -m venv .env
source .env/bin/activate
python -m pip install -e .[dev] # editable install with the 'dev' extra
pytest ...
# re-run install if there are things a normal editable install can't transparently sync, like extension builds
Whereas with uv: uv run --dev pytest ... # uses pytest from the 'dev' dependency group
That single command does everything pip and venv would normally do to prep an editable environment and run pytest. It also works across re-runs, since it'll run `uv sync` as needed under the hood.For example, uv-build is rather lacking in any sort of features (and its documentation barely exists AFAICT, which is a bit disappointing), but uv works just fine with hatchling, using configuration mechanisms that predate uv.
(I spent some time last week porting a project from an old, entirely unsupportable build system to uv + hatchling, and I came out of it every bit as unimpressed by the general state of Python packaging as ever, but I had no real complaints about uv. It would be nice if there was a build system that could go even slightly off the beaten path without writing custom hooks and mostly inferring how they’re supposed to work, though. I’m pretty sure that even the major LLMs only know how to write a Python package configuration because they’ve trained on random blog posts and some GitHub packages that mostly work — they’re certainly not figuring anything out directly from the documentation, nor could they.)
Do library authors have to test against every type checker to ensure maximum compatibility? Do application developers need to limit their use of libraries to ones that support their particular choice of type checker?
Yes, but in practice, the ecosystem mostly tests against mypy. pyright has been making some inroads, mostly because it backs the diagnostics of the default VS Code Python extension.
> Do application developers need to limit their use of libraries to ones that support their particular choice of type checker?
You can provide your own type stubs instead of using the library's built-in types or existing stubs.
I think everyone basically agrees that at the package boundary, you want explicit types, but inside application code things are much more murky.
(plus of course, performance, particularly around incremental processing, which Astral is specifically calling out as a design goal here)
Django does a bunch of magic which is challenging for the type checkers to handle well.
> We are planning to add dedicated Django support at some point, but it's not on our short-term roadmap
[1] https://github.com/astral-sh/ruff/pull/21308#issuecomment-35...
Seems like the code isn't actually open source which to me is a bit concerning. At the very least, if ya'll want to release it like this please be clear that you're not open source. The MIT license in the repo gives the wrong impression.
While we wait... what's everyone's type checking setup? We run both Pyright and Mypy... they catch different errors so we've kept both, but it feels redundant.
https://htmlpreview.github.io/?https://github.com/python/typ... suggests that Pyright is a superset, which hasn't matched our experience.
Though our analysis was ~2 years ago. Anyone with a large Python codebase successfully consolidated to just Pyright?
The spec mostly concerns itself with the semantics of annotations, not diagnostics or inference. I don't really recommend using it as the basis for choosing a type checker.
(I was on the Python Typing Council and helped put together the spec, the conformance test suite, etc)
I suspect pyright has caught up a lot but I turned it off again rather recently.
For what it’s worth I did give up on cursor mostly because basedpyright was very counterproductive for me.
I will say that I’ve seen a lot more vehement trash talking about mypy and gushing about pyright than vice versa for quite a few years. It doesn’t quite add up in my mind.
agreed! mypy's been good to us over the years.
The biggest problem we're looking to solve now is raw speed, type checking is by far the slowest part of our precommit stack which is what got us interested in Ty.
In my case they just add noise when reading code and make it more difficult to review
Ch00k•7h ago