[HN Gopher] Pyrefly: Python type checker and language server in ...
___________________________________________________________________
Pyrefly: Python type checker and language server in Rust
Author : brianzelip
Score : 177 points
Date : 2025-10-14 12:33 UTC (10 hours ago)
(HTM) web link (pyrefly.org)
(TXT) w3m dump (pyrefly.org)
| zelphirkalt wrote:
| Another one I recently discovered and that has a very active
| maintainer is "zuban" or zuban-ls. It has replaced jedi-language-
| server for me, and aims to replace mypy as well.
| f311a wrote:
| Yeah, there are now 3 competitors and they all written in Rust:
|
| - zuban
|
| - ty (from ruff team)
|
| - pyrefly
|
| One year ago, we had none of them, only slow options.
| jerrygenser wrote:
| Basedpyright is not rust but it's a fork of pyright with
| added features that are otherwise locked in vscode
| f311a wrote:
| It's written in Typescript, which is a super weird choice.
| wiseowise wrote:
| Wasn't pyright made specifically for VSCode? That would
| explain TS.
| f311a wrote:
| Yes, but why they did not write it in a compiled
| language? Pyright is pretty slow in large code bases and
| takes a lot of RAM. Javascript can be faster than python
| in some cases, but Python is so easily extendable with
| C,C++, Cython, Rust. They could use Python with one of
| the compiled language.
| IshKebab wrote:
| Because they wanted it to be usable on the web, and I
| guess WASM wasn't where it is right now when they
| started.
| drcongo wrote:
| It's also horrible for fasle positives unless your project
| happens to be the exact same setup as the maintainers' - I
| had to turn off the actual type checking on it. I've since
| moved wholesale to the Ty alpha and it feels a hell of a
| lot smarter.
| JimDabell wrote:
| It also inherits the unfortunate attitude of Pyright that
| it will warn against idiomatic Python (EAFP) in favour of
| non-idiomatic Python (LBYL):
|
| https://github.com/microsoft/pyright/issues/1739
|
| https://docs.python.org/3/glossary.html#term-EAFP
|
| https://docs.python.org/3/glossary.html#term-LBYL
| kstrauser wrote:
| Eww, what? I hadn't seen that before. Yikes, I hope the
| situation's improved. I'd be butting into that
| continually.
| maleldil wrote:
| Sometimes dynamic Python idioms are incompatible with
| typed Python. I personally think that's fine, since I
| consider static typing a significant improvement overall.
| JimDabell wrote:
| This isn't. They actually fixed that bug. Then they
| changed their minds and backed the fix back out again
| _because they don't think you should write Python that
| way_ :
|
| > I think EAFP is a very unfortunate and ill-advised
| practice.
|
| They want you to not write the idiomatic Python:
| try: foo = bar["baz"]["qux"] ...
| except KeyError: ...
|
| ...and instead write the non-idiomatic version:
| if "baz" in bar and "qux" in bar["baz"]: foo
| = bar["baz"]["qux"] ... else:
| ...
|
| If this were a _linter_ then I would accept that it is
| going to be opinionated. But this is not a linter, it's a
| type checker. Their opinions about EAFP are irrelevant.
| That's idiomatic Python.
| IshKebab wrote:
| Well I agree with them. The second code is clearly
| better. Exceptions should be used for error handling and
| if those keys are actually optional then you should
| explicitly check if they exist (or use something like
| `bar.get("baz")`).
| jon-wood wrote:
| I'm sorry, I can't take seriously any piece of software
| which decided to prefix the previous version's name with
| "based". I'm aware this is a me problem.
| cruffle_duffle wrote:
| Hah. I love the name. It implies that whatever the
| original "pyright" was doing wasn't keepin' it real. This
| new version, it's "based" so it must be somehow more
| "real" and "grounded" and "legit".
|
| All I know is it is much more strict about stuff than
| pylance was.
|
| Also a me problem!
| wiseowise wrote:
| Definitely this. I commend author of BPyright, but clown
| (?) avatar, unknown identity of maintainer, and name of
| the fork rub me off wrong way.
| arccy wrote:
| it'll be like python package managers and js web
| frameworks.... a new one every quarter
| vovavili wrote:
| uv works so well for the vast majority of scenarios that I
| don't really see a demand for further innovation in the
| Python package manager domain.
| insane_dreamer wrote:
| it still needs to add handling for binaries (the one
| thing conda can do that uv can't)
| arccy wrote:
| yeah we all heard that story every 3 months with all the
| previous package managers. until there's adoption by an
| overwhelming majority of projects, it isn't really
| settled yet.
| wiseowise wrote:
| I've literally never heard that much buzz and excitement
| about Python tool before. And I've seen them all.
|
| All of them had some big issue that prevented it from
| getting mainstream. Either it was slow, or didn't work
| with existing workflow, or had complex configuration, or
| something that prevented gradual adoption.
|
| uv is universally praised as the second coming Christ in
| Python world (and for a good reason). So no, I doubt
| there will be something else. Not only you need to be
| better than uv, you also need to have community momentum.
| tialaramex wrote:
| Speed is one of those "Quantity has a quality all its own"
| things. We use very fast tools in a qualitatively different
| way, even though all that changed was how long it takes in
| seconds.
|
| It is interesting that nobody was writing these tools in C or
| in C++. There are obvious ergonomic reasons, but perhaps also
| it matters that Rust _cares_ a lot more about types than
| either of those languages.
| f311a wrote:
| It's just very hard to write such systems in C/C++. Even
| all these Rust versions are segfaulting and panicking quite
| a lot. So many corner and edge cases that can be found in
| Python code, and the memory handling is also hard.
|
| The author of Zuban started writing it back in 2020 or
| 2021, so it took him more than 4 years to complete it. And
| he is the author of Jedi, so he had prior experience
| already.
| tialaramex wrote:
| I get why they'd panic, but why have enough segfaults
| that you noticed? So, I went and read the code.
|
| Zuban seems to have a bunch of scary "I'm not sure if
| this is correct" unsafe blocks, which to me would be a
| red flag. I mean, it's better that there's a comment
| expressing the doubt, but my experience is that if you're
| not sure whether it's correct, it's probably not correct.
| estebank wrote:
| While acknowledging the risk of causing a pile-on (which
| I don't want!), would it be possible to have a link to
| them or a description of what the unsafe blocks
| accomplish? I'm intrigued if they are for performance or
| API ergonomics, if they are due to limitations of the
| borrow checker, the stdlib or crate dependencies.
|
| For anyone reaching for unsafe, there are in many cases
| either an existing API (split_at_mut comes to mind). For
| others, using zero-copy or bytemuck instead of unsafe is
| a good idea too.
|
| None of that is to say "never write unsafe", unsafe
| existing is pretty much one of the reasons for Rust to be
| :)
| tialaramex wrote:
| I skimmed these, so this is nothing close to a survey,
| much less a comprehensive review of the software, however
|
| For example in
| crates/zuban_python/src/file/diagnostics.rs:
|
| "TODO this unsafe feels very wrong, because a bit lower
| we might modify the complex/ points."
|
| or crates/zuban_python/src/database.rs:
|
| "Points are guarded by specific logic and if they are
| overwritten by something that shouldn't it should not be
| that tragic."
|
| I saw nothing where I was like "ZOMG this is definitely
| busted" but I definitely did not get the robust "Oh, I
| see now why this is correct" that I like from a good
| unsafe rationale comment, and these aren't tiny things
| like the small unsafe bit twiddling transmutes which are
| probably either actually correct or in any case will do
| what you expected at compile time and so any surprises
| are priced in without a rationale text.
| kibwen wrote:
| _> It is interesting that nobody was writing these tools in
| C or in C++_
|
| This one's easier to explain. People interested in tooling
| for a specific language probably want to write that tooling
| in that language (hence pip, poetry, mypy, jedi, etc).
| Normally that would be the end if it, if Python wasn't
| 10-100x slower than a natively compiled language. And going
| from Python to Rust is an order of magnitude easier than
| going from Python to C or Python to C++, because the
| compiler is so good at identifying silly mistakes. Rust is
| just a friendlier language.
| scosman wrote:
| 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 wrote:
| 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 wrote:
| amazing reply. Thanks!
| underdeserver wrote:
| 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.
| pawelkobojek wrote:
| 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.
| veber-alex wrote:
| Yeah I have a similar experience with ty.
|
| Looks like none of these new type checkers are ready yet.
| f311a wrote:
| 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.
| parhamn wrote:
| Whats the expected error in the example you gave? That x can't
| be none because it was received as a str?
| boxed wrote:
| Or that x is unused?
| pawelkobojek wrote:
| Exactly - something along the lines of "Statement is
| unreachable".
| robertlagrant wrote:
| Yes, exactly. x would have to be str | None to be reachable.
| wiz21c wrote:
| 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 ?
| Austizzle wrote:
| 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
| yesb wrote:
| 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.
| giancarlostoro wrote:
| 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.
| _flux wrote:
| 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 wrote:
| 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.
| Scarblac wrote:
| 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?)
| kstrauser wrote:
| 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 wrote:
| 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 :)
| mixmastamyk wrote:
| The billion dollar mistake.
| kinto wrote:
| 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 wrote:
| 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.
| whalesalad wrote:
| Python is starting to feel a bit like JavaScript circa 2014.
| Remember grunt, gulp, webpack, coffeescript, babel? Now we've got
| pyright, mypy, pyrefly, black, ruff, ty, flake8, poetry, uv...
|
| I used to find this kind of tooling explosion exhausting (and
| back then with JS it truly was), but generally speaking it's a
| good sign that the community is hungry to push things forward.
| Choice is good, as long as we keep the Unix spirit alive: small,
| composable tools that play nicely together and can be
| interchanged.
| strangescript wrote:
| "grunt, gulp, webpack, coffeescript, babel" --- except no one
| uses these anymore and they are dead outside of legacy
| software.
|
| The problem with the python tooling is no one can get it right.
| There aren't clear winners for a lot of the tooling.
| jon-wood wrote:
| I think that's the point. Every now and then a language will
| have a small explosion of new tooling, and all you can really
| do is wait for it to blow over and see what tools people
| adopted afterwards, it feels like Python is going through a
| period like that at the moment.
| parhamn wrote:
| Interestingly besides typescript, javascript in 2025 is still
| super fragmeneted but by a bunch of well-polished tools that
| all do approximately the same thing.
| esbuild/vite(rollup)/trubopack(swc), prettier/biome/oxc,
| npm/bun/pnpm/yarn, bun/node/deno/worker-runtimes
| WesolyKubeczek wrote:
| The fact that you even didn't mention webpack, once a
| champion, is especially sad.
| koakuma-chan wrote:
| Doesn't Next.js still use webpack?
| elsigh wrote:
| It's turbopack time: https://nextjs.org/blog/next-16-beta
| koakuma-chan wrote:
| It's just people refusing to use new tools. Prettier is so
| much slower than any Rust formatter, it's painful. `yarn
| install` takes forever. Why not switch to Bun? It's 5
| minutes.
| koakuma-chan wrote:
| I interviewed at one company a few months ago and they said
| they don't use TypeScript because the compiler gets in
| their way, jesus chirst.
| pjmlp wrote:
| For me it is easy, Spring/Quarkus/ASP.NET, if it has to be a
| JavaScript framework, Next.js the way Vercel intended.
|
| Anything whatever the FE team feels like using, and the less
| I know about it, the better.
| mixmastamyk wrote:
| Next.js has been called infuriating here recently:
| https://news.ycombinator.com/item?id=45099922
| pjmlp wrote:
| I know, search for my nickname and you'll get my point of
| view across several comments.
| pjmlp wrote:
| Pity that is all looking like Rewrite in Rust looking for
| solution, instead of actually improving JIT tooling
| capabilities.
|
| There is a reason us old timers mostly wait on the sidelines
| until the dust settles.
|
| We have seen this movie already too many times.
| notatallshaw wrote:
| A lot of the tools you list here are composable, mypy checks
| type hints, black formats code, because of the purpose and
| design ethos of those two tools they would never think to
| merge.
|
| So which is it that you want, to just reach for one tool or
| have tools that have specific design goals and then have to
| reach for many tools in a full workflow?
|
| FWIW Astral's long term goal appears to be to just reach for
| one tool, hence why you can now do "uv format".
| lenkite wrote:
| "There can be only one" - just need to wait till the
| deathmatches are over.
| IshKebab wrote:
| It's not really that bad. Unless you want to be adventurous you
| need these tools:
|
| * uv: project management, formatting
|
| * Pyright: type checking
|
| * Pylint: linting (this is probably optional though I would
| strongly recommend it). Ruff is an option but I don't think it
| is quite as comprehensive yet.
|
| There are alternatives for those tools but they are pretty
| clearly the best options _at the moment_. There 's nothing in
| uv's league, and the only alternatives in Pyright's league is
| BasedPyright. Hopefully Ty and Pyrefly will be good options in
| future but I don't think they're ready for production use just
| yet.
| dev_l1x_be wrote:
| Is there any meaningful difference between TS and Python?
| bobajeff wrote:
| 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.
| brianzelip wrote:
| See the recent Talk Python podcast featuring some Pyrefly team
| members, https://talkpython.fm/episodes/show/523/pyrefly-fast-
| ide-fri...
| insane_dreamer wrote:
| I've tried pyrefly, ty, pyright, and basedpyright, with a large
| complex code base written using PyCharm, and _none_ of them do as
| good a job as PyCharm, particularly in discovering more complex
| type inheritances. It's a pity because in other respects Zed
| (which relies on these) is a worthy competitor to PyCharm (and
| much faster!) -- but the endless squiggly lines because pyrefly
| can't figure out the type, is annoying (and turning off the
| warnings is unhelpful). Hopefully one of these will get up to
| PyCharm's level (my money would be on ty as Astral is kicking a*
| these days).
| giancarlostoro wrote:
| I think the 2nd best IDE for Python for me is Visual Studio
| proper, not Code. I know it sounds crazy, but Microsoft
| actually put some effort into their Python integration. Again,
| its a 2nd best, but that still says a lot about everyone else's
| editors.
|
| Nowadays I'm finding myself using Zed a lot more, so maybe the
| story will be that all these nice Rust based tools become baked
| in giving it super powers for Python.
| f311a wrote:
| PyCharm has very basic type checking, though. It's not strict.
|
| > pyrefly, ty, pyright, and basedpyright
|
| All of them will complain 2-4x more about your code than
| PyCharm. I had more than 300 typing errors when I first opened
| my 20k LOC project in pyright that I wrote in Pycharm.
|
| PyCharm works great when your code is not annotated. It infers
| types very well. But it won't complain in a lot of cases when
| your code is annotated.
|
| Related reddit post
| https://old.reddit.com/r/Python/comments/1ajnikt/to_pycharm_...
| olejorgenb wrote:
| I don't think these are designed to "discovering" complex type
| inheritances.
|
| They are designed for code which are more or less fully typed,
| as opposed to PyCharm which cobbles together a bunch of
| heuristics to try to make sense out of untyped code. An
| admirable quest, but not one I'm personally interested in.
|
| And their insistence on only supporting this approach drove my
| entire team away from using PyCharm.
|
| (From shallowly observing notifications on the 20+ typehint
| related issues I'm subscribed to, they seem to have kinda
| turned around and working toward fully supporting the python
| type system finally - possibly by integrating with one of the
| third-party type-checkers)
| IshKebab wrote:
| Are you talking about with code that has proper type
| annotations? As I recall PyCharm is about the best you can get
| if you are working with code that has no type annotations but
| ... you shouldn't be doing that in 2025! With type annotations
| I've found Pyright to be 100% rock solid.
| unmotivated-hmn wrote:
| That's interesting. In my experience basedpyright has been
| better than pyCharm at every turn. Yes, a lot more warnings but
| generally sensible. One specific thing I remember pissing me
| off: https://youtrack.jetbrains.com/issue/PY-58665 Still open 2
| years later.
| rasulkireev wrote:
| This looks interesting. But I decided to go with ty in my
| projects, for the incremental approach.
| codethief wrote:
| How well does ty work these days? Last time I checked it still
| produced a lot of false positives and false negatives. (Which
| was very much expected, given its alpha/WIP status.)
| rasulkireev wrote:
| Honestly i barely use it, just started to give it a try by
| adding types where it makes most sense and running with pre-
| commit. No issues so far. But, again, I'm a very light user.
| flanked-evergl wrote:
| Sadly, the question with both this and ty is: Does it support
| pydantic? If not, then it's not really helpful for many people,
| and right now AFAIK neither supports pydantic.
|
| Pydantic is probably the problem here, but it is what it is.
| phailhaus wrote:
| Python's type system is the problem here, which cannot support
| even the native dataclass pattern and needs custom plugins
| written for each type checker.
| kstrauser wrote:
| The type system's alright. It just gets especially tricky
| when you're trying to check code which won't exist until you
| run it. For instance, suppose you wanted to load your own
| module from a database with something like
| foo = eval(result)
|
| It can't know what you're going to load until it actually
| does it.
|
| Things which lean heavily into metaprogramming, typically
| ORMs or things like Pydantic, fall into that category. I
| can't hold that against the type system.
| phailhaus wrote:
| > I can't hold that against the type system.
|
| I think we should. Dataclasses have existed in Python for
| an extremely long time, and yet the type system doesn't
| support defining your own similar classes. Kwargs have also
| existed forever, but they forgot to support that and had to
| add TypedDict's much later. And it still doesn't properly
| support optional fields. There's a lot of stuff like this
| in the language which are unbelievably frustrating, because
| for some reason they implemented the syntax before
| implementing a typechecker. Everything has been hacked in
| ever since. I consider python's type system to be a lost
| cause, just hoping for someone to make the Typescript
| equivalent for Python.
| flanked-evergl wrote:
| I don't think this is really true, I think native data
| classes can do just about everything you need, it's just that
| you need some tooling around them to get the same as Pydantic
| offers. I'm pretty sure we are going to see better native
| dataclass support in Pydantic going forward.
|
| Already there is some support in Pydantic for native
| dataclasses:
| https://docs.pydantic.dev/latest/concepts/dataclasses/
| kitotik wrote:
| I have used native dataclasses with pydantic starting with
| v1.5 and it's only improved with the the newer 2.x
| releases.
|
| Aside from basic inheritance and complex nested types, the
| pydantic 'TypeAdapter' is awesome for simply validating
| native dataclasses. It's a little slow, but everything
| pydantic is =)
| phailhaus wrote:
| There is no facility in the type system to express the idea
| that "whatever class attributes are defined, those are
| kwargs to the init function". That's hacked in using extra
| typechecker plugins. That's why we're sitting around
| talking about if a particular typechecker "supports
| pydantic", rather than it just working.
| flanked-evergl wrote:
| There is a way to indicate whatever class attributes are
| defined, those are kwargs to the init function. For one,
| you can use `kw_only` on the dataclass decorator [1],
| alternatively you can use the `kw_only` arg on the field
| function [2].
|
| [1]: https://docs.python.org/3/library/dataclasses.html#d
| ataclass...
|
| [2]: https://docs.python.org/3/library/dataclasses.html#d
| ataclass...
| ocamoss wrote:
| Pyrefly actually does have (experimental) support for Pydantic!
| https://pyrefly.org/en/docs/pydantic/
| flanked-evergl wrote:
| Nice, did not know.
| mixmastamyk wrote:
| Why would they need to support pydantic when it uses standard
| annotations? I tried it with ty yesterday and it flagged issues
| as expected.
| flanked-evergl wrote:
| Pydantic does some pretty strange stuff which works as
| expected but confuses the type checker unless you use the
| pydantic plugin.
| https://docs.pydantic.dev/latest/integrations/mypy/
| sirfz wrote:
| 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.
| jswny wrote:
| 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
| ehsanu1 wrote:
| Do you assign different responsibilities to different LSP
| servers when there multiple I suppose?
| charliermarsh wrote:
| 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 wrote:
| 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
| screye wrote:
| 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.
| phplovesong wrote:
| If typechecking is tongue on cheek, why even bother?
| atoav wrote:
| If car crashes still kill people, why wear safety belts?
| tremon wrote:
| 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 wrote:
| The analogy would be mandatory inspections of certain
| components or manufacturing processes to see that rules
| and specs are followed while assembling.
| coldtea wrote:
| Because "all or nothing" is a bad idea.
| alfalfasprout wrote:
| > 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.
| fragmede wrote:
| 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.
| dmurray wrote:
| Type checking in Python involves guessing. Take a program
| like
|
| x = [3]
|
| Should the type checker guess that the type of x is
| list[Any], or list[int], or list[Literal[3]], or
| something else? Libraries you depend on will pose more
| difficult versions of this question.
|
| So it's not possible to expect the tool to be "perfect",
| whatever that means - usually people think of it as
| meaning it allows all code that they think is idiomatic
| and reasonable, and disallows all code that could raise a
| TypeError at runtime. You can only expect the tool to be
| reasonably good and perhaps to have an opinionated design
| that matches the way you would like to write Python.
| fragmede wrote:
| Arguably it's the job of a linter and not a type checker,
| but if your code just assigns random things to random
| variables that never get used again, I hope _something_
| would point that out to you before it passes code review
| and merged to main, ideally before it even gets sent for
| review.
|
| Ignoring the question of why there's some random
| assignment to x in the first place, where are its type
| hints? Those were added starting with Python 3.5 via PEP
| 484 just over 10 years ago and have been added to since
| then. If our goal is maintainable code at scale, the
| first thing I'd expect of a type checker is for it to
| communicate with the user, stating that a) the variable
| in file foo.py on line 43 is missing a type hint and
| couldn't be guessed with confidence, and that it's just
| gonna guess it's a list[int]. For bonus points, the tool
| could run in interactive mode and ask the user directly.
| But even without a hint, assuming the variable actually
| is used later, how does it get used?
|
| It seems like you'd just start with the most strict
| interpretation, list[Literal[3]], and relax it as it gets
| used. If it gets fed into a function that doesn't have
| hints and can't be introspected for whatever reason,
| relax it to list[int] and then further relax it to
| list[Any] as necessary. Then depending on the mode the
| user configured the tool to run in, print nothing, or a
| warning, or error out or ask the user what to do if
| running interactively. Some of the config options could
| be strict, tolerant, and loose. Or maybe enforcing,
| permissive, and loose. Whatever color we want this bike
| shed to be.
|
| More advanced tools let the user configure individual
| issues and their corresponding levels, but that may be
| considered too many options to give the user,
| overwhelming the user who then doesn't use the tool.
|
| As far as perfect typing goes, I mean, yeah, ideally,
| after satisfying the type checker in strict mode, which
| means no types need to be guessed at, as all variables
| and other locations without type annotations that need
| them were reported, or even annotated interactively, or
| if we're real fancy, automatically with a comment. IMO
| programs should feel free to edit code directly (as a
| non-default option) That would mean the program could not
| throw an an _uncaught_ TypeError, unexpectedly. That 's a
| lot to ask of a dynamically strongly typed language, but
| I'd settle for it never being utterly wrong.
|
| What that means is if the type checker says the function
| is returning a string, but of the 200 calls to that
| function, the type checker throws an error and says ten
| of those callsites expect it to return a dict, all I'm
| saying is this hypothetical type checker had better be
| right about that. Nothing worse than losing hours rooting
| around in the code looking for something that isn't
| actually there (or an errant semicolon, but this isn't C)
| nickpsecurity wrote:
| 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.
| screye wrote:
| 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.
| kinto wrote:
| 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 wrote:
| 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!
| sheepscreek wrote:
| 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 wrote:
| The weird Literal promotion makes pyrefly unusable for me,
| except if I'd avoid Literal types:
| https://github.com/facebook/pyrefly/issues/742
| eqvinox wrote:
| 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 wrote:
| 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 wrote:
| > 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 wrote:
| > 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 wrote:
| > 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 wrote:
| 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 wrote:
| 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 wrote:
| 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.
| Too wrote:
| 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 wrote:
| 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 wrote:
| (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 wrote:
| 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.
| cadamsdotcom wrote:
| 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!
___________________________________________________________________
(page generated 2025-10-14 23:00 UTC)