Announcing the Beta release of ty
Posted by gavide 1 day ago
Comments
Comment by frou_dh 1 day ago
https://htmlpreview.github.io/?https://github.com/python/typ...
If that table is anything to go by, Pyright is not to be underestimated.
I have briefly tried ty (LSP) in Emacs and it seems to work well so far. The only questionable thing I've encountered is that when the signature of a method is shown, the type annotations of some parameters seem to be presented in a particularly verbose form compared to what I'm used to - maybe they're technically correct but it can be bit much to look at.
Anyway, odds are pretty good that ty is what I will end up using long-term, so thanks and congrats on releasing the first beta!
Comment by hauntsaninja 1 day ago
(I was on the Python Typing Council and helped put together the spec, the conformance test suite, etc)
Comment by SmileyKeith 1 day ago
Comment by hauntsaninja 1 day ago
A shared spec for this is important because if you write a Python library, you don’t want to have to write a different set of types for each Python type checker
Here are some things the spec has nothing to say about:
Inference
You don’t want to annotate every expression in your program. Type checkers have a lot of leeway here and this makes a huge difference to what it feels like to use a type checker.
For instance, mypy will complain about the following, but pyright will not (because it infers the types of unannotated collections as having Any):
x = []
x.append(1)
x[0] + "oops"
The spec has nothing to say about this.Diagnostics
The spec has very little to say about what a type checker should do with all the information it has. Should it complain about unreachable code? Should it complain if you did `if foo` instead of `if foo()` because it’s always true? The line between type checker and linter is murky. Decisions here have nothing to do with “what does this annotation mean”, so are mostly out of scope from the spec.
Configuration
This makes a huge difference when adapting huge codebases to different levels of type checking. Also the defaults really matter, which can be tricky when Python type checkers serve so many different audiences.
Other things the spec doesn’t say anything about: error messages quality, editor integration, speed, long tail of UX issues, implementation of new type system features, plugins, type system extensions or special casing
And then of course there are things we would like to spec but haven’t yet!
Comment by maleldil 1 day ago
This is incorrect. pyright will infer the type of x as list[Unknown].
Comment by hauntsaninja 1 day ago
Unknown is a pyright specific term for inferred Any that is used as the basis for enabling additional diagnostics prohibiting gradual typing.
Notably, this is quite different from TypeScript’s unknown, which is type safe.
Comment by ErikBjare 43 minutes ago
Comment by xixixao 23 hours ago
TypeScript takes the same approach in this scenario, and I assume this helps both be fast.
Comment by solvedd 22 hours ago
Comment by xixixao 12 hours ago
Comment by jitl 14 hours ago
const x = []
x.push(1)
type t = typeof x // number[]Comment by dcre 1 day ago
Edit: Based on this other comment, the point was also about things not covered by the spec. “The spec mostly concerns itself with the semantics of annotations, not diagnostics or inference.” https://news.ycombinator.com/item?id=46296360
Comment by codys 1 day ago
Comment by jghn 12 hours ago
Comment by theLiminator 2 hours ago
Comment by SmileyKeith 1 day ago
Comment by _carljm 1 day ago
Comment by progbits 1 day ago
That said I'm very happy user of uv, so once Ty becomes ready enough will be happy to migrate.
Comment by conception 1 day ago
Comment by WD-42 1 day ago
Comment by morkalork 1 day ago
Comment by cmclaughlin 1 day ago
Comment by linhns 15 hours ago
Comment by melodyogonna 11 hours ago
Comment by wiz21c 1 day ago
Comment by ameliaquining 16 hours ago
Comment by SSchick 1 day ago
PR is somewhat WIP-ish but I needed some motivation to do OSS work again :)
Comment by CyberThijs 20 hours ago
https://htmlpreview.github.io/?https://github.com/SimonSchic...
Comment by collinmanderson 15 hours ago
I really need better generics support before ty becomes useful. Currently decorators just make all return types unknown. I need something this to work:
_F = TypeVar("_F", bound=Callable[..., Any])
def my_decorator(*args: str) -> Callable[[_F], _F]: ...
Also, I use a lot of TypedDicts and there's not much support yet.Comment by IshKebab 1 day ago
Mypy is trash. Nice to have a table to point to to prove it.
Comment by klysm 1 day ago
Comment by amanzi 1 day ago
I agree though. Hope this is successful and they keep building awesome open-source tools.
Comment by jbmsf 1 day ago
It's definitely a narrow path for them to tread. Feels like the best case is something like Hashicorp, great until the founders don't want to do it anymore.
Comment by embedding-shape 21 hours ago
Wow, that's probably my go-to case of things going south, not "best case scenario". They sold to IBM, a famous graveyard for software, and on the way there changed from FOSS licensing to their own proprietary ones for software the community started to rely on.
Comment by jbmsf 8 hours ago
Comment by embedding-shape 8 hours ago
You might be on to something with point B, hard to find good examples of developer tool companies that don't eventually turn sour. However, there are countless examples of successful and still very useful developer tools out there, maybe slapping a company on it and sell a "pro" version isn't the way to go?
Comment by clircle 1 day ago
Comment by tabbott 1 day ago
Comment by tyre 1 day ago
Comment by bmitc 1 day ago
Comment by woodruffw 1 day ago
Comment by amluto 1 day ago
As a very basic example I ran into last week, Python tooling, even the nice Astral tooling, seems to be almost completely lacking any good detection of what source changes need to trigger what rebuild steps. Unless I’ve missed something, if I make a change to a source tree that uv sync doesn’t notice, I’m stuck with uv pip install -e ., which is a wee bit disappointing and feels a bit gross. I suppose I could try to put something correct into cache-keys, but this is fundamentally wrong. The list of files in my source tree that need to trigger a refresh is something that my build system determines when it builds. Maybe there should be a way to either plumb that into uv’s cache or to tell uv that at least “uv sync” should run the designated command to (incrementally) rebuild my source tree?
(Not that I can blame uv for failing to magically exfiltrate metadata from the black box that is hatchling plus its plugins.)
Comment by woodruffw 1 day ago
It's really helpful to have examples for this, like the one you provide below (which I'll respond to!). I've been a maintainer and contributor to the PyPA standard tooling for years, and once uv "clicked" for me I didn't find myself having to leave the imperative layer (of uv add/sync/etc) at all.
> As a very basic example I ran into last week, Python tooling, even the nice Astral tooling, seems to be almost completely lacking any good detection of what source changes need to trigger what rebuild steps.
Could you say more about your setup here? By "rebuild steps" I'm inferring you mean an editable install (versus a sdist/bdist build) -- in general `uv sync` should work in that scenario, including for non-trivial things where e.g. an extension build has to be re-run. In other words, if you do `uv sync` instead of `uv pip install -e .`, that should generally work.
However, to take a step back from that: IMO the nicer way to use uv is to not run `uv sync` that much. Instead, you can generally use `uv run ...` to auto-sync and run your development tooling within an environment than includes your editable installation.
By way of example, here's what I would traditionally do:
python -m venv .env
source .env/bin/activate
python -m pip install -e .[dev] # editable install with the 'dev' extra
pytest ...
# re-run install if there are things a normal editable install can't transparently sync, like extension builds
Whereas with uv: uv run --dev pytest ... # uses pytest from the 'dev' dependency group
That single command does everything pip and venv would normally do to prep an editable environment and run pytest. It also works across re-runs, since it'll run `uv sync` as needed under the hood.Comment by amluto 8 hours ago
Python builds via [tool.hatch.build.targets.wheel.hooks.custom] in pyproject.toml and a hatch_build.py that invokes waf and force-includes the .so files into useful locations.
Use case 1: Development. I change something (C/C++ source, the waf configuration, etc) and then try to run Python code (via uv sync, uv run, or activating a venv with an editable install). Since there doesn't seem to be a way to have the build feed dependencies out to uv (this seems to be a deficiency in PEP 517/660), I either need to somehow statically generate cache-keys or resort to reinstall-package to get uv commands to notice when something changed. I can force the issue with uv pip install -e ., although apparently I can also force the issue with uv run/sync --reinstall-packages [distro name]. [0] So I guess uv pip is not actually needed here.
It would be very nice if there was an extension to PEP 660 that would allow the editable build to tell the front-end what its computed dependencies are.
Use case 2: Production
IMO uv sync and uv run have no place in production. I do not want my server to resolve dependencies or create environments at all, let alone by magic, when I am running a release of my software built for the purpose.
My code has, long before pyproject.toml or uv was a thing and even before virtual environments existed (!), had a script to build a production artifact. The resulting artifact makes its way to a server, and the code in it gets run. If I want to use dependencies as found by uv, or if I want to use entrypoints (a massive improvement over rolling my own way to actually invoke a Python program!), as far as I can tell I can either manually make and populate a venv using uv venv and uv pip or I can use UV_PROJECT_ENVIRONMENT with uv sync and abuse uv sync to imperatively create a venv.
Maybe some day uv will come up with a better way to produce production artifacts. (And maybe in the distant future, the libc world will come up with a decent way to make C/C++ virtual environments that don't rely on mount namespaces or chroot.)
[0] As far as I can tell, the accepted terminology is that the thing produced by a pyproject.toml is possibly a "project" or a "distribution" and that these are both very much distinct from a "package". I think it's a bit regrettable that uv's option here is spelled like it rebuilds a _package_ when the thing you feed it is not the name of a package and it does not rebuild a particular package. In uv's defense, PEP 517 itself seems rather confused as well.
Comment by polski-g 13 hours ago
Various tickets asking for it, but they also want to bundle in the python interpreter itself, which is out of scope for a pyproject.toml manager: https://github.com/astral-sh/uv/issues/5802
Comment by amluto 1 day ago
For example, uv-build is rather lacking in any sort of features (and its documentation barely exists AFAICT, which is a bit disappointing), but uv works just fine with hatchling, using configuration mechanisms that predate uv.
(I spent some time last week porting a project from an old, entirely unsupportable build system to uv + hatchling, and I came out of it every bit as unimpressed by the general state of Python packaging as ever, but I had no real complaints about uv. It would be nice if there was a build system that could go even slightly off the beaten path without writing custom hooks and mostly inferring how they’re supposed to work, though. I’m pretty sure that even the major LLMs only know how to write a Python package configuration because they’ve trained on random blog posts and some GitHub packages that mostly work — they’re certainly not figuring anything out directly from the documentation, nor could they.)
Comment by Gabrys1 21 hours ago
Comment by eyeris 1 day ago
Comment by BiteCode_dev 1 day ago
Comment by shrumm 1 day ago
While we wait... what's everyone's type checking setup? We run both Pyright and Mypy... they catch different errors so we've kept both, but it feels redundant.
https://htmlpreview.github.io/?https://github.com/python/typ... suggests that Pyright is a superset, which hasn't matched our experience.
Though our analysis was ~2 years ago. Anyone with a large Python codebase successfully consolidated to just Pyright?
Comment by gwking 1 day ago
I suspect pyright has caught up a lot but I turned it off again rather recently.
For what it’s worth I did give up on cursor mostly because basedpyright was very counterproductive for me.
I will say that I’ve seen a lot more vehement trash talking about mypy and gushing about pyright than vice versa for quite a few years. It doesn’t quite add up in my mind.
Comment by hauntsaninja 1 day ago
Comment by shrumm 1 day ago
agreed! mypy's been good to us over the years.
The biggest problem we're looking to solve now is raw speed, type checking is by far the slowest part of our precommit stack which is what got us interested in Ty.
Comment by hauntsaninja 1 day ago
The spec mostly concerns itself with the semantics of annotations, not diagnostics or inference. I don't really recommend using it as the basis for choosing a type checker.
(I was on the Python Typing Council and helped put together the spec, the conformance test suite, etc)
Comment by modeless 1 day ago
I've been using Pyrefly and loving it compared to Pyright, but they recently shipped some updates with crash bugs that forced me to pin to a previous version, which is annoying. Unfortunately my first impression of ty isn't great either. Trying to install the ty extension on the current version of Cursor says "Can't install 'astral-sh.ty' extension because it is not compatible with the current version of Cursor (version 2.2.20, VSCode version 1.105.1)."
Comment by ocamoss 1 day ago
Comment by charliermarsh 1 day ago
Comment by modeless 1 day ago
If I choose "install previous version" I am able to install the pre-release version from 12 hours ago without issue. Then on the extension page I get a button labeled "Switch to Release Version" and when I press it I get an error that says "Can't install release version of 'ty' extension because it has no release version." Filed a GitHub issue with these details.
In the meantime, the previous version appears to be working well! I like that it worked without any configuration. The Pyrefly extension needed a config tweak to work.
Comment by _carljm 1 day ago
Comment by modeless 1 day ago
Comment by _carljm 1 day ago
Comment by chombier 22 hours ago
Both are rust/open-source/new/fast so it's difficult to understand why I should choose one over the other.
Comment by pansa2 1 day ago
Do library authors have to test against every type checker to ensure maximum compatibility? Do application developers need to limit their use of libraries to ones that support their particular choice of type checker?
Comment by carderne 1 day ago
So only the outer API surface of the library matters. That’s mostly explicitly typed functions and classes so the room for different interpretations is lower (but not gone).
This is obviously out the window for libraries like Pydantic, Django etc with type semantics that aren’t really covered by the spec.
Comment by WD-42 1 day ago
Comment by MangoToupe 1 day ago
Comment by dragonwriter 1 day ago
Comment by dwattttt 1 day ago
x = []
x.append(1)
x[0] = "new"
x[0] + "oops"
It's optionally typed, but I would credit both "type checks correctly" and "can't assign 'new' over a number" as valid type checker results.Comment by jitl 14 hours ago
const x = []
x.push(1)
type t = typeof x
// ^? type t = number[]
x[0] = "new"
type t2 = typeof x
// ^? type t2 = (number | string)[]
const y = x[0] + "oops"
// ^? const y: string
https://www.typescriptlang.org/play/?#code/GYVwdgxgLglg9mABA...Comment by kurtis_reed 23 hours ago
Comment by MangoToupe 1 day ago
Either way, you didn't annotate the code so it's kind of pointless to discuss.
Also fwiw python is typed regardless of the annotations; types are not optional in any sense. Unless you're using BCPL or forth or something like that
Comment by dwattttt 1 day ago
There are several literals in that code snippet; I could annotate them with their types, and this code would still be exactly as it is. You asked why there are competing type checkers, and the fact that the language is only optionally typed means ambiguity like that example exists, and should be a warning/bug/allowed; choose the type checker that most closely matches the semantics you want to impose.
Comment by dragonwriter 1 day ago
Well, no, there is one literal that has an ambiguous type, and if you annotated its type, it would resolve entirely the question of what a typechecker should say; literally the entire reason it is an open question is because that one literal is not annotated.
Comment by dwattttt 1 day ago
Comment by MangoToupe 16 hours ago
Optimally, this will result in a democratic consensus of semantics.
Pessimistically, this will result in dialects of semantics that result in dialects of runtime languages as folks adopt type checkers.
Comment by dragonwriter 16 hours ago
That hasn't been a fact for quite a while. Npw, it does specify the semantics of its type annotations. It didn't when it first created annotations for Python 3.0 (PEP 3107), but it has progressively since, starting with Python 3.5 (PEP 484) through several subsequent PEPs including creation of the Python Typing Council (PEP 729).
Comment by MangoToupe 9 hours ago
Comment by MangoToupe 16 hours ago
Well, no, you didn't. Because it's not clear whether the list is a list of value or a list of values of a distinct type. And there are many other ways you could quibble with this statement.
Comment by sagarm 1 day ago
Comment by mikepurvis 1 day ago
I think everyone basically agrees that at the package boundary, you want explicit types, but inside application code things are much more murky.
(plus of course, performance, particularly around incremental processing, which Astral is specifically calling out as a design goal here)
Comment by mirashii 1 day ago
Yes, but in practice, the ecosystem mostly tests against mypy. pyright has been making some inroads, mostly because it backs the diagnostics of the default VS Code Python extension.
> Do application developers need to limit their use of libraries to ones that support their particular choice of type checker?
You can provide your own type stubs instead of using the library's built-in types or existing stubs.
Comment by lou1306 23 hours ago
Comment by caidan 23 hours ago
In fact as Jetbrains has been spending years chasing various rabbits including AI, instead of substantially improving or fixing PyCharm, without you steadily replacing/repairing big chunks of Pycharms functionality I would be miserable. If it came down to it, we would happily pay a reasonable license fee to use your tools as long as they stayed free for non-commercial usage.
Comment by linhns 15 hours ago
Comment by collinmcnulty 1 day ago
Comment by Ch00k 1 day ago
Comment by BiteCode_dev 1 hour ago
Pyright/pylance were a boon because they were the first non-pycharm good implementation.
But they still have rough edges and will fail from time to time, not to mention the latency.
Comment by fkarg 1 day ago
Comment by albert_e 21 hours ago
I recently viewed tutorials on uv and ruff from Corey Schafer on youtube which were excellent
Hope to make these tools part of my defaults
Look forward a similar overview by Corey on ty :)
Curious ..is there any backstory to these library names?
Comment by japhyr 20 hours ago
Comment by benrutter 15 hours ago
[0] https://talkpython.fm/episodes/download/520/pyx-the-other-si...
Comment by zanie 14 hours ago
Comment by collinmanderson 14 hours ago
ruff - "RUst Formatter".
ty - "TYpe checker"
uv - "Unified python packaging Versioner"? or "UniVersal python packaging"
Comment by BiteCode_dev 1 hour ago
Comment by benrutter 10 hours ago
Comment by akdor1154 1 day ago
Comment by 0cf8612b2e1e 1 day ago
Django does a bunch of magic which is challenging for the type checkers to handle well.
Comment by selcuka 1 day ago
Comment by 0cf8612b2e1e 1 day ago
Comment by selcuka 1 day ago
> We are planning to add dedicated Django support at some point, but it's not on our short-term roadmap
[1] https://github.com/astral-sh/ruff/pull/21308#issuecomment-35...
Comment by czue 5 hours ago
Comment by tabbott 1 day ago
Comment by f311a 1 day ago
Also, it's also too bad we have three competing fast LSP/typechecker projects now We had zero 1 year ago.
Comment by iamdanieljohns 1 day ago
Comment by arthur-st 20 hours ago
Comment by maccard 20 hours ago
Comment by pcwelder 1 day ago
It's fast too as promised.
However, it doesn't work well with TypedDicts and that's a show-stopper for us. Hoping to see that support soon.
Comment by sharkdp 1 day ago
Comment by pcwelder 1 day ago
from anthropic.types import MessageParam
data: list[MessageParam] = [{"role": "user", "content": [{"type": "text", "text": ""}]}]
```
This for example works both in mypy and pyright. (Also autocompletion of typedict keys / literals from pylance is missing)
Comment by sharkdp 23 hours ago
I reported this as https://github.com/astral-sh/ty/issues/1994
Support for auto-completing TypedDict keys is tracked here: https://github.com/astral-sh/ty/issues/86
Comment by superlopuh 21 hours ago
Comment by dcreager 16 hours ago
[1] https://github.com/astral-sh/ruff/blob/0bd7a94c2732c232cc142...
[2] https://github.com/astral-sh/ruff/blob/0bd7a94c2732c232cc142...
Comment by numbers 1 day ago
Comment by pansa2 1 day ago
Comment by Svoka 1 day ago
Comment by lysecret 1 day ago
Comment by maxloh 1 day ago
Comment by danudey 1 day ago
Comment by parham 1 day ago
Comment by Zababa 1 day ago
Comment by wiseowise 23 hours ago
``` It's recommended to disable the language server from the Python extension to avoid running two Python language servers by adding the following setting to your settings.json:
{ "python.languageServer": "None" } ```
Comment by petesergeant 23 hours ago
Comment by woodruffw 16 hours ago
Comment by dcreager 16 hours ago
Comment by ReflectedImage 23 hours ago
The point is you drop things such as types to enable rapid iteration which enables you to converge to the unknownable business requirements faster.
If you want slow development with types, why not Java?
Comment by maccard 20 hours ago
Comment by solarkraft 21 hours ago
Comment by philipallstar 22 hours ago
It's not a prototyping language or a scripting language or whatever. It's just a language. And types are useful, especially when you can opt out of type checking when you need to. Most of the time you don't want to be reassigning variables to be different types anyway, even though occasionally an escape hatch is nice.
Comment by falcor84 23 hours ago
> RUFF 0.14.9
> UV 0.9.18
> TY 0.0.2
> PYX Beta
> GITHUB
Comment by hexo 1 day ago
Comment by sails01 1 day ago
Comment by wiseowise 23 hours ago
> Akshually, are there any studies showing that cars riding 30 km/h kill less people than cars that ride 80 km/h?
Comment by dllthomas 20 hours ago
Comment by kurtis_reed 23 hours ago
Comment by hexo 1 day ago
Comment by sails01 1 day ago
In my case they just add noise when reading code and make it more difficult to review
Comment by solarkraft 21 hours ago
Comment by bmitc 1 day ago
Comment by pansa2 1 day ago
Comment by sails01 1 day ago
Comment by dragonwriter 1 day ago
No, static typing is usually used AOT (most frequently at compile time), not usually at runtime (types may or may not exist at runtime; they don't in Haskell, for instance.)
Python type checking is also AOT, but (unlike where it is inextricably tied to compilation because types are not only checked but used for code generation) it is optional to actually do that step.
Python type annotations exist and are sometimes used at runtime, but not usually at that point for type checking in the usual sense.
Comment by tome 20 hours ago
> No, static typing is usually used AOT (most frequently at compile time), not usually at runtime (types may or may not exist at runtime; they don't in Haskell, for instance.)
In fact, Haskell then allows you to add back in runtime types using Typeable!
https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-...
Comment by amethyst 1 day ago
Comment by wiseowise 23 hours ago
Educate yourself before making such claims.
Comment by almanael 1 day ago
Comment by zanie 1 day ago
> At time of writing, many of the remaining rules require type inference and/or multi-file analysis, and aren't ready to be implemented in Ruff.
ty is actually a big step in this direction as it provides multi-file analysis and type inference.
(I work at Astral)
Comment by int_19h 2 hours ago
Comment by caidan 23 hours ago
Comment by syiblet 1 day ago
Seems like the code isn't actually open source which to me is a bit concerning. At the very least, if ya'll want to release it like this please be clear that you're not open source. The MIT license in the repo gives the wrong impression.
Comment by woodruffw 1 day ago
Comment by zanie 1 day ago
Comment by simonw 1 day ago
Comment by bobthecowboy 1 day ago