Looks like you found the not-so-secret repository we're using to prepare for a broader announcement :)
Please be aware this is pre-alpha software. The current version is 0.0.0a6 and the releases so far are all in service of validating our release process. We're excited to get this in people's hands, but want to set the expectation that we still have a lot of work left to do before this is production ready.
Stay tuned for more for news in the near future!
(... I work at Astral)
(where "not otherwise typecheckable" means types that can't be expressed with stubs - e.g., Django, dataclasses pre-PEP-681, pytest fixtures, etc.)
(It's also more difficult to support plugins effectively in a type checker like ty, than in a linter like ruff, since any non-trivial use case would likely require deep changes to how we represent types and how we implement type inference. That's not something that lends itself to a couple of simple hook extension points.)
For example, as my recent struggles showed, SQLAlchemy breaks `pyright` in all kinds of ways. Compared with how other 'dynamic' ORMs like Prisma interact with types, it's just a disaster and makes type checking applications that use it almost pointless.
How does Ty play with SQLAlchemy?
Ty could solve this if they rebel and decide to ignore the Python typing standards, which I honestly would appreciate, but if they take the sensible approach and follow the standards, it won't change anything.
I don’t know about SQLAlchemy, but for libraries like pandas I just don’t see how it can be done, and so people are actively replacing them with modern typed alternatives
Is this all based off a spec that python provides? If so, what does that look like?
Or do you "recode" the python language in rust, then use rust features to parse the python files?
Regardless of how it's done - This is a really fascinating project, and I'm really glad you guys are doing it!
https://github.com/python/cpython/blob/main/Parser/Python.as...
ty uses the same AST and parser as ruff. We don't use the ASDL grammar directly, because we store a few syntax nodes differently internally than how they're represented upstream. Our parser is hand-written in Rust. At first, our AST was also entirely hand-written, though we're moving in the direction of auto-generating more of it from a declarative grammar.
https://github.com/astral-sh/ruff/issues/15655
https://github.com/astral-sh/ruff/tree/main/crates/ruff_pyth...
https://github.com/astral-sh/ruff/blob/main/crates/ruff_pyth...
CPython uses a generated parser. The grammar is defined in https://github.com/python/cpython/blob/main/Grammar/python.g... which is used to generate the specification at https://docs.python.org/3/reference/grammar.html#full-gramma...
We use a hand-written parser, in Rust, based on the specification. We've written that previously at https://astral.sh/blog/ruff-v0.4.0#a-hand-written-parser
For years I pushed black for formatting code. Once formatting was baked into ruff I ditched black. Having fewer dependencies to track and update simplifies my life and shortens my dependabot queue.
No, they are correctly using semantic versioning to indicate pre-alpha releases. https://github.com/astral-sh/ty/releases https://semver.org/
What am I missing here?
The reason we're stuck on mypy at work is because it's the only type checker that has a plugin for Django that properly manages to type check its crazy runtime generated methods.
I wish more python tooling took the TS approach of "what's in the wild IS the language", as opposed to a "we only typecheck the constructs we think you SHOULD be using".
Or in this case, writing it in Rust...
mypy is written in Python. People have forgotten that Python is really, really slow for CPU-intensive operations. Python's performance may not matter when you're writing web service code and the bottlenecks are database I/O and network calls, but for a tool that's loading up files, parsing into an AST, etc, it's no surprise that Rust/C/even Go would be an order of magnitude or two faster than Python.
uv and ruff have been fantastic for me. ty is definitely not production ready (I see several bizarre issues on a test codebase, such as claiming `datetime.UTC` doesn't exist) but I trust that Astral will match the "crazy reality" of real Python (which I agree, is very crazy).
This is a known issue — we're currently defaulting to a conservative Python version, and `datetime.UTC` really doesn't exist until Python 3.11!
https://docs.python.org/3/library/datetime.html#datetime.UTC
We will probably change the default to "most recent supported Python version", but as mentioned elsewhere, this is very early and we're still working out these kinds of kinks!
Currently we default to our oldest supported Python version, in which `datetime.UTC` really doesn't exist! Use `--python-version 3.12` on the CLI, or add a `ty.toml` with e.g.
``` [environment] python-version = "3.12" ```
And we'll find `datetime.UTC`.
We've discussed that this is probably the wrong default, and plan to change it.
There are some extremely CPU-intensive low-level operations that you can easily write in C and expose as a Python API, like what Numpy and Pandas do. You can then write really efficient algorithms in pure Python. As long as those low-level operations are fast, those Python-only algorithms will also be fast.
I don't think this is necessarily "cheating" or "just calling disguised C functions." As an example, you can write an efficient linear regression algorithm with Numpy, even though there's nothing in Numpy that supports linear regression specifically, it's just one of the ways a Python programmer can arrange Numpy's low-level primitives. If you invent some new numerical algorithm to solve some esoteric problem in chemistry, you may be able to implement it efficiently in Python too, even if you're literally the first person ever writing it in any language.
The actual problem is that it's hard for people to get an intuition of which Python operations can be made fast and which can't, AST and file manipulation are sadly in the latter group.
This gives somewhat counterintuitive results where declaring and summing a whole list of integers in memory can be faster than a simple for loop with an iterator.
But yeah writing stuff in a different (compiled) language is often better if that means the python interpreter doesn't need to go through as many steps.
TS might transpile to JS and can always be split into a js and type annotation file but is it's own language developed in tandem with the type check based on a holistisch approach to find how to type check then and then put it into the syntax and type checker.
Thats not true for python at all.
Python types where added as annotations to the language many years ago, but not in a holistic approach but in simplistic approach only adding some fundamental support and then extended bit by bit over the years (and not always consistently).
Furthermore this annotations are not limited to type checking which can confuse a type checker (through Annotated helps a lot, but is also verbose, wonder how long until there is a "Annotated" short syntax e.g. by impl @ on type or similar).
Basically what the type annotation feature was initially intended to be and what it is now differ quite a bit (dump example `list` vs. `List`, `Annotated` etc.).
This is made worse that a bunch of "magic" is deeply rooted in python, e.g. sub-classing `Enum`. Sure you have that in JS too, and it also doesn't work that well in TS (if you don't add annotation on the dynamically produced type).
Lastly TS is structurally typed, which allows handling a bunch of dynamic typing edge cases, while Python is, well, in-between. Duck-typing is (simplified) structural typing but `isinstance` is a common thing in Python and is nominal typing...
So yeah it's a mess in python and to make it worse there bunch of annoyances related to ambiguity or to many ways how to do a thing (e.g. re-exports+private modules, you can do that common coding pattern, but it sucks badly).
Or how make a wrapper function with args and kwargs to pass through?
[1]: https://docs.python.org/3/library/typing.html#typing.datacla...
(And uv and ruff have basically proved that at this point)
which brings us to another python issue, python is quite bad at such huge refactoring even with type checkers
but yeah python is by far the slowest widely used language, and for some use cases you can side step it by placing most hot code in C++/Rust extension modules, (or don't care because you are much much more network latency bound) but a type checker probably doesn't belong into that category
And not directly related, but I wish more python modules did proper checks with Valgrind before shipping.
Nah, that's just part of the parade of excuses that comes out any time existing software solutions get smoked by a newcomer in performance, or when existing software gets more slow and bloated.
Here's one of many examples:
https://m.youtube.com/watch?v=GC-0tCy4P1U&pp=0gcJCdgAo7VqN5t...
not because they don't want to or because it's to slow
but because it's not really viable without fully executing module loading in a sandbox, which might seem viable until you realize that you still need to type check `__main__` modules etc. and that its a common trend in python to do configs by loading python modules and grabbing the module locals as keys of the config or loading some things might actually idk. initialize a GPU driver :sob: So it's kinda 100% guaranteed not possible to do fully correct type checking for all project :smh:
But also python is one of the slowest popular languages (and with a large margin to any not also "one of slowest" languages). Only by moving hot code into C++/Rust is it fast, which often is good enough, but a type checker is exactly this kind of software where this approach stops working.
- mypy (warm cache) 18s
- ty: 0.5s (and found 3500 errors)
They've done it again.
This is an early preview of a pre-alpha tool, so I would expect a good chunk of those 3500 errors to be wrong at at this point :) Bug reports welcome!
I was also one of those people who, when first trying Ruff, assumed that it didn't work the first time I ran it because of how fast it executed!
I would like to just not use it, but the existence of pyright as a _barely_ functional alternative really sucks the air out of other attempts' continued existence. Real "extend/extinguish" behavior from MSFT.
Ty: 2.5 seconds, 1599 diagnostics, almost all of which are false positives
Pyright: 13.6 seconds, 10 errors, all of which are actually real errors
There's plenty of potential here, but Ty's type inference is just not as sophisticated as Pyright's at this time. That's not surprising given it hasn't even been released yet.
Whether Ty will still perform so much faster once all of Pyright's type inference abilities have been matched or implemented - well, that remains to be seen.
Pyright runs on Node, so I would expect it to be a little slower than Ty, but perhaps not by very much, since modern JS engines are already quite fast and perform within a factor of ~2-3x of Rust. That said, I'm rooting for Ty here, since even a 2-3x performance boost would be useful.
> This project is still in development and is not ready for production use.
Indeed they have. Similar improvement in performance on my side.
It is so fast that I thought it must have failed and not actually checked my whole project.
uvx ty check cd /tmp
git clone https://github.com/simonw/sqlite-utils
cd sqlite-utils
uvx ty check
Here's the output: https://gist.github.com/simonw/a13e1720b03e23783ae668eca7f6f...Adding "time uvx ty check" shows it took:
uvx ty check 0.18s user 0.07s system 228% cpu 0.109 total uv tool install ty
Then you can use it anywhere ty check uv tool run ty
If your $PATH sucksastral have now replaced the awful pip with the fantastic uv
various awful linters with with the fantastic ruff
and now hopefully replacing the terrible type checkers (e.g. mypy) with a good one!
I hope they have the pypi backend on their list too, my kingdom for Maven Central in python!
I would concur with you if you said Go, Rust, Ruby, or even heck, PHP, but Java is probably the only language that I know that is in a situation even as bad as Python or even worse (at least for me definitely worse, because at least I understand Python tooling enough even when using it only for hobby projects, while I still don't understand Java tooling enough even after working professionally with JVM languages for 7+ years).
Java is the only language that I know except Python that has multiple project/package managers (Maven, Gradle, probably even more). It also has no concept of lock files in at least Maven/Gradle, and while resolution dependency in Maven/Gradle is supposed to be deterministic, from my experience it is anything but: just a few weeks ago we had a deployment that failed but worked locally/CI because of dependency resolution somehow pulled different versions of the same library.
Fighting dependency hell because different dependencies pull different version constraints is a pain (all Java/JVM projects that I ever worked had some manually pinned dependencies to either fix security issues or to fix broken dependency resolution), and don't even get me in the concept of Uber JARs (that we had to use in previous job because it was the only way to ensure that the dependency tree would be solved correctly; yes maybe it was by incompetence of the team that maintained our shared libraries, but the fact that we even got at that situation is unacceptable).
Oh, and also Gradle is "so fun": it is a DSL that has zero discovery (I had IntelliJ IDEA Ultimate and I could still not get it to auto-complete 60% of the time), so I would just blindly try to discover what where the inputs of the functions. The documentation didn't help because the DSL was so dynamic and every project would use it slightly different, so it was really difficult to discover a way to make it work for that specific project (the examples that I would find would be enough different from my current project that 90% of time it wouldn't work without changing something). Python at least has `pyproject.toml` nowadays, and the documentation from PyPA is good enough that you can understand what you want to do after reading it for 10 minutes.
Modular.ai raised $100 million to solve tangentially similar problems with python. Astral has already had a much larger impact, while providing better integration with less than 10% of that money.
you could even say that astral and modular focus on two extreme ends of the developer experience spectrum - just making python tooling faster, vs making python-ish code faster.
IIRC they have floated the idea of private registries as a commercial offering in the past.
Pylance is borked on these forked distributions, so having a new solid alternative here that doesn't involve adopting yet another forked Pyright implementation (BasedPyright, Cursor Pyright, Windsurf Pyright, ...) sounds great to me.
> basedpyright re-implements many features exclusive to pylance - microsoft's closed-source extension that can't be used outside of vscode.
This is especially important when working in a team setting.
It doesn't feel great to use a forked type checker/LSP that's not enforced in your org's CI/CD. And it also doesn't feel great to force the forked type checker onto the entire organization when only a subset of folks may be using a forked vscode editor.
Talk is cheap, and people talk a lot about supporting projects.
Maybe if we could make some kind of statistics over the number of projects that were abandoned because maintainers didn't feel like working and dealing with random people for free anymore. Make the consequences of freeloading visible somehow.
With that being said, the worst case scenario is that they go caput, but that still leaves the python community with a set of incredible new rust-based tools. So definitely a net win for the python community either way!
Not making any sort of ethical statement, just interesting that rust keeps eating the python and JS tooling worlds.
Astral announced they were building a typechecker back in January: https://x.com/charliermarsh/status/1884651482009477368
https://github.com/facebook/pyrefly/blob/a8626110da034f8e513...
(However, vc-backed astral probably need control over theirs to keep monetization options open, and Facebook probably need control over theirs so it can be targeted at Facebook's internal cool-but-non-standard python habits... Sigh.
Why do we have nice things? Money. Why can't we have nice things? Also money.)
in python eco system you have linters like ruff which do hardly any type checking and type checkers like mypy which do try to approach complete type checking, but still are absurdly full of holes
2. speed
any of the "established" type checkers either are supper slow (e.g. mypy) so you only run it like once before commit instead of "life" or do fail to properly type check so many things that if you have a requirement for "adequate static code analysis" they reliably fail that requirement (which might result in a legal liability, but even if not is supper bad for reliable code and long term maintenance)
also probably priorities are switched with 1st speed then closing holes as the later part is really hard due to how a mess python typing is (but in many code bases most code won't run into this holes so it's okay, well except if you idk. use pyalchemy as "ORM" subclassing base model (just don't terrible idea)).
On the modest codebase I tried it on (14k LOC across 126 files), it runs in 149ms compared to 1.66s in pyright (both run via uvx <tool>). I couldn't get it to play nicely with a poetry project, but it works fine (obviously) in a uv project.
Definitely some false-positives, as expected. Interestingly, it seems to hate the `dict()` initializer (e.g. `dict(foo="bar")`).
Ruff's linting and formatting is more likely to get plugin/extension support at some point in the future.
Ruff is a linter which (intentionally) does close to no type checking.
So you pretty much have to pair it up with a type check to get any even just half way decent static code analysis.
When it was released it might have been one of the easiest to use languages.
The focus on tooling and making the tooling fast has been sharp. Seeing people recommend using non-astral tooling seems nuts at this point.
But I like that they’re focussing on creating something useful before chasing revenue. Once they’ve got a single tool that provides a consistent dev experience for Python developers and it’s widely adopted they should be able to pursue monetisation easily.
"An age" is probably an attempted cleaning-up of "a coon's age."
Thanks for all your great work! Love ruff, rye/uv.
lint:unresolved-import: Cannot resolve imported module `pydantic` --> vartia/usr_id.py:4:6 | 2 | from typing import Optional, Any 3 | from enum import Enum 4 | from pydantic import BaseModel, ConfigDict
looking forward to the release version.
For now, I have some false negative warnings :
'global' variables are flagged as undefined `int:unresolved-reference: Name ... used when not defined` (yeah, it's bad, I know)
f(*args) flagged as missing arguments `lint:missing-argument: No arguments provided for required parameters ...`
Also currently the Python IDE support (autocompletion, refactoring, etc.) in VSCode is provided by Pylance which is closed source, so this would provide an open source alternative to that.
[bring on the downvotes]
Not every situation calls for type safe languages, you're projecting a preference.