sirfz 2 days 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 days 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 2 days 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 2 days 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 days 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 2 days 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.

fragmede 2 days 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.
dmurray 2 days ago [-]
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 2 days ago [-]
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)

dmurray 2 days ago [-]
> 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.

The code is in a third party library which doesn't have comprehensive type hints, and perhaps has type expectations so complicated that they can't be expressed in the Python type system.

Even if you enforce type hints on every line in your internal code, you're going to be relying at some point on libraries which are reliable but poorly type hinted. If you're not using that vast ecosystem of libraries, Python probably wasn't the best choice.

nickpsecurity 2 days 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.
phplovesong 2 days ago [-]
If typechecking is tongue on cheek, why even bother?
atoav 2 days ago [-]
If car crashes still kill people, why wear safety belts?
phplovesong 9 hours ago [-]
Thats a bad analogy. A better one is should we check the breaks before (compile time) we start the car and drive down the highway (runtime).

At this point you either did check the breaks, or did not. If not you are out of luck if the breaks did infact not work.

fastasucan 3 hours ago [-]
Or you test the breaks as you stop to see that everything is clear as you exit your driveway and go into the street.
tremon 2 days 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 2 days ago [-]
The analogy would be mandatory inspections of certain components or manufacturing processes to see that rules and specs are followed while assembling.
coldtea 2 days ago [-]
Because "all or nothing" is a bad idea.
phplovesong 9 hours ago [-]
How so? We have multiple languages with static types, and most know the insane benefit you get from having compile time guardrails.
jswny 2 days 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 2 days 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!
jswny 2 days ago [-]
Good to know, I had no idea!
sirfz 2 days 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 days ago [-]
Do you assign different responsibilities to different LSP servers when there multiple I suppose?
2 days ago [-]
scosman 2 days 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 2 days 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 2 days ago [-]
amazing reply. Thanks!
underdeserver 2 days 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.

whalesalad 2 days ago [-]
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.

parhamn 2 days ago [-]
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
koakuma-chan 2 days ago [-]
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 2 days ago [-]
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.
WesolyKubeczek 2 days ago [-]
The fact that you even didn't mention webpack, once a champion, is especially sad.
koakuma-chan 2 days ago [-]
Doesn't Next.js still use webpack?
elsigh 2 days ago [-]
pjmlp 2 days ago [-]
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 2 days ago [-]
Next.js has been called infuriating here recently: https://news.ycombinator.com/item?id=45099922
pjmlp 2 days ago [-]
I know, search for my nickname and you'll get my point of view across several comments.
IshKebab 2 days ago [-]
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.

notatallshaw 2 days ago [-]
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 2 days ago [-]
"There can be only one" - just need to wait till the deathmatches are over.
dev_l1x_be 2 days ago [-]
Is there any meaningful difference between TS and Python?
pjmlp 2 days ago [-]
One uses runtimes that ship a state of the art JIT compiler, whereas the other is only now giving the first steps.

Yes there are alternatives to CPython, unfortunely they aren't adopted as much as they should.

strangescript 2 days ago [-]
"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 2 days ago [-]
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.
pjmlp 2 days ago [-]
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.

brianzelip 2 days ago [-]
See the recent Talk Python podcast featuring some Pyrefly team members, https://talkpython.fm/episodes/show/523/pyrefly-fast-ide-fri...
insane_dreamer 2 days ago [-]
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).
f311a 2 days ago [-]
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 2 days ago [-]
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)

giancarlostoro 2 days ago [-]
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.

unmotivated-hmn 2 days ago [-]
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.
IshKebab 2 days ago [-]
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.
pawelkobojek 2 days 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 days 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 2 days 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 2 days 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 2 days 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 2 days 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 :)
pjmlp 2 days ago [-]
Yes, but you also need to turn the warning into an error for it to be actually usable, because .NET team didn't want to break the ecosystem, plenty of Assemblies out there didn't cared to update themselves.

I still have to disable nullable types in some delivery projects.

Scarblac 2 days 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 2 days 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 2 days 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.
scuff3d 2 days ago [-]
In Zig you have to mark variables as nullable when they are declared. If you try to assign null to any variable that doesn't have it marked as such the program won't compile.

Any nullable type has to be unwrapped before accessing the value, or again, won't compile.

mixmastamyk 2 days ago [-]
The billion dollar mistake.
parhamn 2 days ago [-]
Whats the expected error in the example you gave? That x can't be none because it was received as a str?
robertlagrant 2 days ago [-]
Yes, exactly. x would have to be str | None to be reachable.
pawelkobojek 2 days ago [-]
Exactly - something along the lines of "Statement is unreachable".
wiz21c 2 days 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 2 days 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 2 days 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 2 days ago [-]
Or that x is unused?
veber-alex 2 days ago [-]
Yeah I have a similar experience with ty.

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

f311a 2 days 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.
eqvinox 2 days 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 2 days 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 2 days 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 2 days 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 2 days 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 2 days 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 days 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 :)

sh34r 2 days ago [-]
It is a purely subjective design decision, but I personally prefer the stricter rules that don’t do backwards type inferences like this… type hints shouldn’t follow duck typing semantics. Otherwise you’re not providing nearly as much value IMO. Typescript is really the model organism here. They took the most cursed mainstream programming language, and made it downright good.

Today, the “: list[str]” is 11 wasted characters and it’s not as aesthetically pleasing. Tomorrow, you do some refactor and your inferred list[str] becomes a list[int] without you realizing it… I’m sure that sounds silly in this toy example, but just imagine it’s a much more complex piece of code. The fact of the matter is, you declared foo as a list[any] and you’re passing it to a function that takes an iterable[str] — it ought to complain at you! Type hints are optional in Python, and you can tell linters to suppress warnings in a scope with a comment too.

That being said, perhaps these more permissive rules might be useful in a legacy codebase where no type annotations exist yet.

Really, it’d be extra nice if they made this behavior configurable, but I’m probably asking for too much there. What’s next, a transpiler? Dogs and cats living together?!

eqvinox 1 days ago [-]
> Today, the “: list[str]” is 11 wasted characters and it’s not as aesthetically pleasing. Tomorrow, you do some refactor and your inferred list[str] becomes a list[int] without you realizing it… I’m sure that sounds silly in this toy example, but just imagine it’s a much more complex piece of code.

Hmm. I'm looking at a codebase that is still in a lot of "early flux", where one day I might be looking at a "list[VirtualRouter]" but the next day it's a "list[VirtualRouterSpec]". It's already gone through several refactors and it kinda felt like the type hints were pretty much spot on in terms of effort-benefit. It's not a legacy codebase; it has reasonably good type hint coverage, but it's focused on type hinting interfaces (a few Protocol in there), classes and functions. The type hinting inline in actual code is limited.

I do understand your perspective, but tbh to me it feels like if I went that far I might rather not choose Python to begin with…

notatallshaw 2 days 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.
bobajeff 2 days 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 2 days 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 2 days ago [-]
The weird Literal promotion makes pyrefly unusable for me, except if I'd avoid Literal types: https://github.com/facebook/pyrefly/issues/742
Too 2 days 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.
cadamsdotcom 2 days 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!

rasulkireev 2 days ago [-]
This looks interesting. But I decided to go with ty in my projects, for the incremental approach.
codethief 2 days ago [-]
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 2 days ago [-]
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.
natdempk 2 days 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 2 days 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 2 days 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.
2 days ago [-]
zelphirkalt 2 days ago [-]
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 2 days ago [-]
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.

tialaramex 2 days ago [-]
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.

kibwen 2 days ago [-]
> 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.

f311a 2 days ago [-]
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 2 days ago [-]
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 2 days ago [-]
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 2 days ago [-]
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.

jerrygenser 2 days ago [-]
Basedpyright is not rust but it's a fork of pyright with added features that are otherwise locked in vscode
f311a 2 days ago [-]
It's written in Typescript, which is a super weird choice.
wiseowise 2 days ago [-]
Wasn’t pyright made specifically for VSCode? That would explain TS.
f311a 2 days ago [-]
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 2 days ago [-]
Because they wanted it to be usable on the web, and I guess WASM wasn't where it is right now when they started.
huflungdung 2 days ago [-]
[dead]
drcongo 2 days ago [-]
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 2 days ago [-]
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

maleldil 2 days ago [-]
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 2 days ago [-]
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 2 days ago [-]
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")`).
JimDabell 2 days ago [-]
You are welcome to that opinion, but type checkers should not be opinionated, especially if they push people to write non-idiomatic Python. If you think this should be written a different way, that’s what lint rules are for.
IshKebab 2 days ago [-]
Actually Python type checkers must be opinionated. Python doesn't define the semantics of type annotations so type checkers have to choose them.

They don't always choose the same options, so some Python code may type check in one type checker and not in another.

Yes this is a dumb situation but that's how it is. So Pyright has to make a choice here, and they chose the most sensible option.

You're free to disagree of course.

kstrauser 2 days ago [-]
Eww, what? I hadn’t seen that before. Yikes, I hope the situation’s improved. I’d be butting into that continually.
2 days ago [-]
jon-wood 2 days ago [-]
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.
wiseowise 2 days ago [-]
Definitely this. I commend author of BPyright, but clown (?) avatar, unknown identity of maintainer, and name of the fork rub me off wrong way.
cruffle_duffle 2 days ago [-]
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!

arccy 2 days ago [-]
it'll be like python package managers and js web frameworks.... a new one every quarter
vovavili 2 days ago [-]
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.
arccy 2 days ago [-]
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 2 days ago [-]
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.

pjmlp 2 days ago [-]
Using Python in one form or the other since Python 1.6, there is always some buzz for whatever tool now and then.
insane_dreamer 2 days ago [-]
it still needs to add handling for binaries (the one thing conda can do that uv can't)
rana762 2 days ago [-]
[dead]
flanked-evergl 2 days ago [-]
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.

ocamoss 2 days ago [-]
Pyrefly actually does have (experimental) support for Pydantic! https://pyrefly.org/en/docs/pydantic/
flanked-evergl 2 days ago [-]
Nice, did not know.
mixmastamyk 2 days ago [-]
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 2 days ago [-]
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/
mixmastamyk 2 days ago [-]
I see. Tried ty and it seemed to know about missing required args. But wasn't able to follow the Field directives.
phailhaus 2 days ago [-]
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 2 days ago [-]
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 2 days ago [-]
> 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 2 days ago [-]
Dataclasses support optional fields and kwargs perfectly. Not sure what you are talking about.

I don't think you understand what Pydantic brings to the table or why people use it. It has lots more to do with serialization, complex validation and data mapping.

phailhaus 8 hours ago [-]
kwargs are not dataclasses, they are dicts. TypedDict was shoehorned in later to allow typing dicts, but they are so poorly designed that you can't mark individual fields as optional.
bvrmn 2 days ago [-]
I guess you didn't work with good type system then. Look for TS, for example. How it allows to make strong typing for pydantic-like libraries in FE world. All how it allows to type routers.
flanked-evergl 2 days ago [-]
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/

phailhaus 2 days ago [-]
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.
bvrmn 2 days ago [-]
Technically there is dataclass_transform [1]. It's an ungodly hack, I don't know how it passed PEP review. And support by type checkers is questionable. After TS python hints feels like rigid and total unsound mess.

[1]: https://docs.python.org/3/library/typing.html#typing.datacla...

flanked-evergl 2 days ago [-]
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#dataclass...

[2]: https://docs.python.org/3/library/dataclasses.html#dataclass...

phailhaus 2 hours ago [-]
That's only for dataclasses, you can't implement your own class like this without implementing it as a dataclass, because the typechecking for it is hacked in as a custom plugin.

What I'm trying to point out is that these features exist in core Python and yet the type system they built can't express it. By contrast, TypeScript is designed in such a way that you can implement everything yourself without having to write "custom typescript checker plugins".

kitotik 2 days ago [-]
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 =)