Top
Best
New

Posted by brianzelip 6 hours ago

Pyrefly: Python type checker and language server in Rust(pyrefly.org)
157 points | 117 comments
sirfz 5 hours ago|
I've decided to to try out Pyrefly, Ty and Zuban for their language server features (type checking disabled where possible) last week and found that Zuban is the fastest (but unfortunately doesn't currently have the option to disable type checking). Ty comes next and Pyrefly was surprisingly slow to load (have to wait a few seconds before I can goto definition for example).

They all lack certain features vs basedpyright (what I was using) such as auto imports (Ty has experimental support), showing signature/doc when selecting autocomplete options (I think Ty does have this one) and some other features that I can't remember.

One feature that always existed in Jedi (and now also Zuban) is "goto declaration" in Python. It allowed me to goto the "import" instead of the original definition of a function/class which I'm surprised either isn't supported at all (pyright?) or would just do the same thing as "goto definition" (Ty), seems like an obvious oversight imho.

Edit: Also, I wish all these new tools give more importance to such IDE features as much as they do for type checking.

kinto 2 hours ago||
Hey, Pyrefly developer here, thanks for trying us out!

We're dedicated to providing a great IDE experience, though it does take some time. Please bother us on github / our discord if you have features you want - bug reports / community asks are our biggest priority.

- auto import is implemented in Pyrefly: it uses your pyrefly.toml project structure or falls back to your VSCode workspace (up to the first 2500 files). we're happy to fix it for your situation if you want to provide a reproduction

- signature/doc when selecting autocomplete options is a known bug [here](https://github.com/facebook/pyrefly/issues/1090)

- go to declaration: I've created an issue for that [here](https://github.com/facebook/pyrefly/issues/1291), it should be quick.

- speed: by far the biggest issue. your problem is likely related to [this](https://github.com/facebook/pyrefly/issues/360) but we need more information to speed it up. we're happy to work with you to to improve this if you're willing to provide a project structure

sirfz 53 minutes ago||
Hi, thanks for the links and for opening the goto declaration issue (that's awesome). I will try to dedicate more time into my setup and provide feedback where possible. Looking forward for all the new updates!
screye 4 hours ago|||
If ruff & uv have proved anything, it's that a tool that's effortless, a net-positive and fast will get adopted.

New typecheckers don't need to be perfect. They need to be good enough, easy to integrate and have low false positives. Sure, they will improve with time, but if feels like a pain then no one will pick it up. Python users are famously averse to tools that slow down their dev cycles, even if it means better long term stability

BasedPyright is popular because it comes built-in with Cursor and disappears into the background. I have a positive bias towards Astral figuring it out given their track record. But, none of these tools have reached the point of effortlessness just yet.

alfalfasprout 2 hours ago|||
> New typecheckers don't need to be perfect. They need to be good enough, easy to integrate and have low false positives. Sure, they will improve with time, but if feels like a pain then no one will pick it up. Python users are famously averse to tools that slow down their dev cycles, even if it means better long term stability

I really don't agree. Sure, they don't need to be perfect but also keep in mind many codebases have already standardized on something like (based)pyright or mypy. So there's a migration cost. If your analysis has a lot of false positives or misses a lot of what those type checkers miss then there's little incentive to migrate. Sure, ty and pyrefly are much faster, but at the end of the day speed is only one consideration for a type checker.

screye 53 minutes ago|||
Think of it this way. There are 2 groups. Group 1 has has avoided typecheckers because they're a PITA and group 2 has configured mypy/pyright despite the devx pain. Group 1 is a lot bigger than group 2. Group 2 is more lucrative per unit than group 1.

With enough time, ty and pyrefly will approach perfectness. If they're easy enough to use today, group 1 should be able to adopt them without any extra pain. (some typechecker is better than no typechecker). This gives them momentum. In couple of years, ty/pyrefly may finally be better than mypy/pyright. Then, Group 2 can start their ports.

This way, no one misses out. Group 2 still gets their perfect typechecker, just not immediately. But in that time, Group 1 is getting familiar with using typecheckers and their sheer size helps build institutional momentum towards typecheckers as an essential piece of any python dev flow.

If A. 'certain class of python problems are permanently solved by typecheckers' and B. 'every python user has some typechecker' become true, then that opens a lot of doors. Today, B is a harder problem than A. I'm guessing that compiled/JIT python will be the next frontier once python typing is solved. Wide typechecker adoption is a blocking requirement for that door to be opened.

nickpsecurity 1 hour ago||||
Also, in the past, many tools were dumped by users for too many false positives. Tools like Astree and RV-Match got adoption by having no or low false positives.
fragmede 2 hours ago|||
No, I'm pretty sure they need to be perfect. If the tool's telling me bad information about types, first I'm going to lose a stupid amount of time debugging to that wrong info, and then swear off the tool forever after I realize it was the tool that was wrong.
phplovesong 3 hours ago|||
If typechecking is tongue on cheek, why even bother?
coldtea 2 hours ago|||
Because "all or nothing" is a bad idea.
atoav 3 hours ago|||
If car crashes still kill people, why wear safety belts?
tremon 2 hours ago||
I don't think that's an accurate metaphor. Seatbelts are expressly a runtime solution to car crashes, whereas Python's type checking is a) only done during development (not even during build), and b) completely reliant on third-party tools.

If you're looking for a car analogy, I would suggest comparing Python type checking to installing speed cameras on the factory floor.

ObscureScience 35 minutes ago||
The analogy would be mandatory inspections of certain components or manufacturing processes to see that rules and specs are followed while assembling.
jswny 4 hours ago|||
At least for Ty, not sure about the others, it is explicitly for type checking, exposed as an LSP. It’s not trying to compete with full LSP implementations. Most modern editors let you combine multiple LSPs, you shouldn’t think of them as using only one at a time
charliermarsh 1 hour ago|||
We actually do want ty to be a first-class LSP (i.e., a complete alternative to Pylance and others), and it already supports nearly all of the features you'd expect. I use it as my primary LSP today in lieu of Pylance!
sirfz 56 minutes ago||||
I understand your confusion because at first look it seems like it's just a type checker (same issue with pyrefly and zuban) hence my comment about bringing forward the fact it's a fully featured lsp
ehsanu1 2 hours ago|||
Do you assign different responsibilities to different LSP servers when there multiple I suppose?
cadamsdotcom 16 minutes ago||
Been using pyrefly since July on a big python build.

It has some things it can’t pick up on - no return after a catch block when all code paths are covered for example - but it’s speedy and the error messages are good enough for Claude to understand and ignore or resolve.

Recommended!

scosman 6 hours ago||
Anyone know how this compares to 'ty': a new typechecker from Astral (uv/ruff team), also written in Rust and super fast. I had been waiting on it to reach beta, but would love to move to something faster than pyright sooner if possible.
emddudley 6 hours ago|
Pyrefly vs. ty: Comparing Python’s Two New Rust-Based Type Checkers (2025-05-27) https://blog.edward-li.com/tech/comparing-pyrefly-vs-ty/

HN discussion of above: https://news.ycombinator.com/item?id=44107655

How Well Do New Python Type Checkers Conform? A Deep Dive into Ty, Pyrefly, and Zuban (2025-08-29) https://sinon.github.io/future-python-type-checkers/

scosman 4 hours ago||
amazing reply. Thanks!
underdeserver 37 minutes ago||
A note - the second link talks mostly about conformance with a standard suite of tests, only briefly touching on real-world use.

I would very much like to understand how good Zuban is today compared to the competition.

brianzelip 5 hours ago||
See the recent Talk Python podcast featuring some Pyrefly team members, https://talkpython.fm/episodes/show/523/pyrefly-fast-ide-fri...
eqvinox 4 hours ago||
Hm, it doesn't seem to be dealing particularly well with imported packages that don't have type annotations. Seeing a bunch of "has no attribute" warnings. Some of the "substitute" annotations also seem to be wrong (e.g. asyncio in CPython has no annotations [in my installed version], but it's pulling some in from somewhere and they're not quite right…) It's also getting confused about lists and tuples in __slots__.
notatallshaw 4 hours ago|
The standard library does not directly include type hints, they are stored in typeshed: https://github.com/python/typeshed

You can take a look yourself if you think some of them are wrong: https://github.com/python/typeshed/tree/main/stdlib/asyncio

The advantage is type hints can be fixed without needing to release a new version of Python. The disadvantage is there's a lot of code in the standard library that doesn't really consider how to represent it with type hints, and it can be really tricky and not always possible.

I'm surprised to see so many people moving to pyrefly, ty, and zuban so quickly. I was going to wait until some time in 2026 to see which has matured to the point I find useful, I guess some users really find existing solutions actually unworkable.

eqvinox 3 hours ago||
> You can take a look yourself if you think some of them are wrong: https://github.com/python/typeshed/tree/main/stdlib/asyncio

Hmm. Presumably mypy and pyrefly use the same ones, but then I don't understand why pyrefly is complaining and mypy isn't:

  ERROR Argument `Future[list[BaseException | Any]]` is not assignable to parameter `future` with type `Awaitable[tuple[Any]]` in function `asyncio.events.AbstractEventLoop.run_until_complete` [bad-argument-type]
     --> xxx/xxx.py:513:33
      |
  513 |         loop.run_until_complete(tasks.gather(*x, return_exceptions=True))
      |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The definition in typeshed is this:

  def run_until_complete(self, future: _AwaitableLike[_T]) -> _T: ...
…where is it even puling "tuple[Any]" from…

(tbh this is rather insignificant compared to the noise from external packages without type annotations, or with incomplete ones… pyrefly's inferences at the existence of attributes and their types are extremely conservative…)

notatallshaw 3 hours ago||
> Hmm. Presumably mypy and pyrefly use the same ones, but then I don't understand why pyrefly is complaining and mypy isn't:

> …where is it even puling "tuple[Any]" from…

Perhaps it's a bug in pyrefly, perhaps mypy or pyrefly is able to infer something about the types that the other isn't. I would strongly suggest checking their issues page, and if not seeing a report already report it yourself.

While there is an ongoing push to more consistently document the typing spec: https://typing.python.org/. It does not actually cover all the things you can infer from type hints, and different type hint checkers have decided to take different design choices compared to mypy and will produce different errors even in the most ideal situation.

This is one of the reasons why I am waiting for these libraries to mature a little more.

eqvinox 3 hours ago||
> it does not actually cover what rules you can check or infer from type hints

Indeed this is the cause of maybe 30% of the warnings I'm seeing… items being added to lists or dicts in some place (or something else making it infer a container type), and pyrefly then refusing other types getting added elsewhere. The most "egregious" one I saw was:

  def something(x: list[str]) -> str:
      foo = []
      for i in x:
          foo.append(i)
      return "".join(foo)
Where it complains:

  ERROR Argument `str` is not assignable to parameter `object` with type `LiteralString` in function `list.append` [bad-argument-type]
   --> test.py:4:20
  4 |         foo.append(i)
Edit: now that I have posted it, this might actually be a bug in the .join type annotation… or something

Edit: nah, it's the loop (and the LiteralString variant of .join is just the first overload listed in the type hints)… https://github.com/facebook/pyrefly/issues/1107 - this is kinda important, I don't think I can use it before this is improved :/

notatallshaw 3 hours ago||
I assume in your example if you update the foo declaration to the following it solves the complaint:

    foo: list[str] = []
If so this a type checking design choice:

  * What can I infer from an empty collection declaration?
  * What do I allow further down the code to update inferences further up the code?
I don't know Pyrefly's philosophy here, but I assume it's guided by opinionated coding guidelines inside Meta, not what is perhaps the easiest for users to understand.
eqvinox 2 hours ago||
Yes, annotating the type explicitly fixes it; but tbh I'd consider that type annotation "unnecessary/distracting code litter".

As far as their philosophy goes, it's an open issue they're working on, so their philosophy seems to agree this particular pattern should work :)

notatallshaw 1 hour ago||
I agree, but as a type checker it is a subjective choice, whether to be explicit and not make assumptions or whether to infer from certain certain patterns as probably correct and not be noisy to the user. Very glad to see they plan to fix this.
pawelkobojek 6 hours ago||
I love the speed advantage of pyrefly over (based)pyright but so far it doesn't seem to highlight as much as pyright does, for example it doesn't catch unreachable code like this:

  def fn(x: str):
    if x is None:
      x = "123"  # pyright flags that as unreachable code, pyrefly does not
Autocomplete for modules also doesn't work for me yet:

  import os
  os.  # I'll get `ABC, `Any`, `AnyStr`, `AnyStr_co`, `BinaryIO`, ...
Looking forward to have a fast language server for python though, pyright is way too slow for large projects.
kinto 2 hours ago||
Hey, Pyrefly developer here, thanks for trying us out! Thanks for bearing with us with these issues you're experiencing while we're still in alpha.

We're planning on adding unreachable code diagnostics soon (github issue [here](https://github.com/facebook/pyrefly/issues/1292)). These come for free with Pyright so we don't want to regress features.

I'm happy to help diagnose/fix your autocomplete issue: it should work on modules. If you want to provide details here, on [discord](https://discord.gg/Cf7mFQtW7W), or as a Github issue (github/discord preferred) we'll fix it for you + anyone else with the problem.

pawelkobojek 59 minutes ago||
I absolutely understand this is still alpha so I kind of assumed these are expected. Frankly, that's why I haven't submitted an issue -- I assumed it's going to be fixed at some point. I'll go ahead and make an issue on GitHub, thanks.
giancarlostoro 5 hours ago|||
It's funny because in other typed languages a string can be null because of string being a reference type as opposed to a value type. I think Python type hints make more sense than C# does in this respect, which gives me a chuckle (two of my favorite languages and the untyped one makes more sense with types). That said, not sure if you already have but I would add a github issue / ticket reporting your issue to raise awareness to the devs.
kstrauser 4 hours ago|||
A quibble: Python is strongly typed. It’s not un-typed in any reasonable sense of the word. It’s dynamically typed, though: type information is on objects, not on the names referring to them.
seabrookmx 3 hours ago||||
If you use the nullable types compiler option in C# (which defaults to enabled for new projects) then you need to declare you string as string? for it to be nullable :)
Scarblac 4 hours ago||||
All Python types are reference types. The reference to None isn't included in the str type.

There's no way to get an actual null reference, afaik. Variables always have some value, possibly None.

(not sure what happens if you set a reference to null from C - a crash, probably?)

_flux 5 hours ago||||
In some other typed languages, that is. E.g. in C++, OCaml, Haskell, F#, Kotlin, and Rust (a non-exhaustive list) you can have non-nullable strings, and other objects.
asplake 4 hours ago||
It’s worth noting that even though the runtime allows nulls (i.e. None) anywhere, Python type checkers do distinguish between optional and mandatory types.
mixmastamyk 1 hour ago|||
The billion dollar mistake.
parhamn 5 hours ago|||
Whats the expected error in the example you gave? That x can't be none because it was received as a str?
robertlagrant 5 hours ago|||
Yes, exactly. x would have to be str | None to be reachable.
pawelkobojek 5 hours ago||||
Exactly - something along the lines of "Statement is unreachable".
wiz21c 4 hours ago||||
isn't it perfectly valid to pass None to that function ? It's not like python enforces types at runtime nor at compile time. Right ?
yesb 4 hours ago|||
Sure, it's valid python to do that. By that logic you could also pass an int. But the context of this post is that you're using a static type checker.
Austizzle 4 hours ago|||
It's not valid from a typing perspective, but python will let you. If you want to disregard types though then none of this matters anyway and you won't get much benefit from these tools
boxed 5 hours ago|||
Or that x is unused?
veber-alex 5 hours ago||
Yeah I have a similar experience with ty.

Looks like none of these new type checkers are ready yet.

f311a 5 hours ago||
Ty has autocomplete for imports, but it's hidden behind a toggle right now. They are still working on it. They index all the modules and functions, so you can just type the function name and it will suggest the correct import and insert it.
Too 2 hours ago||
Anyone struggling with slow mypy should really update to latest version. This years releases has focused on performance and it has payed off. Add the boost from latest Python versions to that and you can see 50% type checking improvements. Still far from a rust based tool, always something, all without changing your tool chain.
natdempk 2 hours ago||
Anyone here know what the ideal/best setup is for typechecking + LSPing Django these days?

I've been leaning on pyright + django-stubs, but wondering if I'm missing something better with fewer gaps and pain points.

kinto 1 hour ago||
(Pyrefly dev here)

We've seen a lot of people have success with the mypy plugin + django-stubs.

Full out-of-the-box support is being actively worked on in Pyrefly: we will have specialized django enum support in the next release and we expect real experimental support by the end of the year. At that time we'll likely post a blog post to announce it [here](https://pyrefly.org/blog/).

nprateem 52 minutes ago||
Just started trying ty with django-types. I got the models typed in a day or so. Still wading through the other 200+ errors in my codebase. But it's fast at least.
bobajeff 5 hours ago||
Though, I'm happy with basedpyright and usually disable type checking. It's great to have so many options in language servers for Python now that pylance is locked to vscode.
sheepscreek 4 hours ago|
I much prefer the rigidity of pyrefly. It enforces a standard expectation across the code base, which will lead to less surprises IMO.
whilenot-dev 3 hours ago|
The weird Literal promotion makes pyrefly unusable for me, except if I'd avoid Literal types: https://github.com/facebook/pyrefly/issues/742
More comments...