
Pybites Podcast
The Pybites Podcast is a podcast about Python Development, Career and Mindset skills.
Hosted by the Co-Founders, Bob Belderbos and Julian Sequeira, this podcast is for anyone interested in Python and looking for tips, tricks and concepts related to Career + Mindset.
For more information on Pybites, visit us at https://pybit.es and connect with us on LinkedIn:
Julian: https://www.linkedin.com/in/juliansequeira/
Bob: https://www.linkedin.com/in/bbelderbos/
Pybites Podcast
#199: Charlie Marsh on ty, uv, and the Python tooling renaissance
Charlie Marsh returns to Pybites to introduce ty —Astral’s bold new take on Python type checking. Built from the ground up for speed and developer experience, ty is both a command-line tool and language server, powered by Rust's Salsa framework.
We dive into how it enables lightning-fast incremental analysis, smarter diagnostics inspired by Rust, and a reimagined type-checking workflow for modern Python projects. Charlie also shares how Astral is tackling broader ecosystem challenges alongside Meta and NVIDIA.
Curious? Just run 'uv x ty' and join the future of Python type checking.
For more info check out the following:
Notes & Blog Posts: https://notes.crmarsh.com/
LinkedIn: https://www.linkedin.com/in/marshcharles/
GitHub: https://github.com/charliermarsh
X: https://x.com/charliermarsh
GitHub Repo: https://github.com/astral-sh/ty
Explaining rust-analyzer (lectures): https://www.youtube.com/playlist?list=PLhb66M_x9UmrqXhQuIpWC5VgTdrGxMx3y
___
💡🧑💻Level up your Python skills in just 6 weeks with our hands-on, mentor-led cohort program. Build and ship real apps while gaining confidence and accountability in a supportive community. Join a Pybites Developer Cohort today! 🌟✅
___
If you found this podcast helpful, please consider following us!
Start Here with Pybites: https://pybit.es
Developer Mindset Newsletter: https://pybit.es/newsletter 💡
Pybites Books: https://pybitesbooks.com/
Bob LinkedIn: https://www.linkedin.com/in/bbelderbos/
Julian LinkedIn: https://www.linkedin.com/in/juliansequeira/
Twitter: https://x.com/pybites
Apple Podcasts: https://podcasts.apple.com/us/podcast/pybites-podcast/id1545551340
Spotify: https://open.spotify.com/show/1sJnriPKKVgPIX7UU9PIN1
I think it's safe to say that we will have the most advanced like incrementality model of any Python type checker, and that's been a big part of the design. And again that comes from these desires of like. We want to build a great type checker and a great language server and they have things that are in common but they also have, like, very different requirements and if you don't think about both of those from the start, you end up in a little bit of trouble.
Julian:Hello and welcome to the PyBytes podcast, where we talk about Python career and mindset. We're your hosts. I'm Julian Sequeira and I am Bob.
Bob:Eldeboos, if you're looking to improve your Python, your career and learn the mindset for success, this is the podcast for you. Let's get started. Hello and welcome back everybody to the PyBytes podcast. This is is Bob Beldebus, and I'm here with Charlie Marsh. Charlie, welcome back.
Charlie:Yeah, thanks so much for having me back on the show.
Bob:Yeah, our pleasure. How are you?
Charlie:doing today. I'm good. I'm good. I mentioned this to you in the pre-show, but we had a kid like two months ago, so it's our second kid, so it's a little bit fewer unknowns this time. But yeah, I guess I could just say I'm busy trying to balance a lot, but I'm excited to do this today.
Bob:Congratulations, yeah, thanks.
Julian:Thank you.
Bob:Must be a lot to balance.
Charlie:Yeah, yeah, yeah yeah.
Bob:So, yeah, this is the second time we had you on 175. So people can also listen to that. And yeah, there we spoke a lot about Ruff and UV and UV was just coming out. Well, it was out but had a lot of changes and you keep adding stuff. I saw that UV has a new build system now as well. It just keeps innovating, right.
Charlie:Yeah, that's right.
Charlie:I mean I think we're trying to balance, like doing more things, solving more user problems, with trying to avoid bloating the tool, and I think we're doing that successfully so far.
Charlie:But you know, I guess we do say no to a lot of things. But like a build system is something we wanted to do basically from the start, because we found that without our own build system, especially for new users or beginners, they would run into really confusing experiences because they'd be using UV with another build system like setup tools or hatchling, which are great build systems, but if they didn't really know what the difference was between like the build system and UV, they'd get really confused if they dropped into UV and started getting errors from hatchling or setup tools or had to go learn those tools. So for us, it was something we always wanted to do, which was provide a more, at least for more straightforward use cases, provide a sort of a simpler, more integrated experience. So, yeah, I'm glad we shipped that. That's now stable. We use it for all of our own stuff. That's pure Python and we've been doing that for a while. So, yeah, excited to get that out there.
Bob:Yeah and now you're kind of getting the whole tool chain right, because now TY is out I mean pre-release but now building a type checker as well, which is a humongous yeah, so yeah, we can focus our discussion on that, but of course, yeah, we can also pull it back into the the greater uh theme of you know, helping the python ecosystem uh become more effective in their tooling right yes absolutely so. Yeah, before, uh, we dive into ty and a question about that. Um yeah, do you have a particular win of the week?
Charlie:you wanted to share a win of the week um, let me see we've been working on some really interesting stuff, um, with meta and nvidia and a couple other companies focused on uh, a new set of uh extensions to the python or a new things you want to propose as changes to the Python packaging ecosystem, largely focused on like how do we make Python packaging better for, especially for like hardware, accelerated use cases, like if you're using like CUDA or GPUs. It's kind of the strength of Python, right, that you can like install PyTorch and it like run stuff on CUDA and you don't have to really think too much. Like CUDA or GPUs. Um, it's kind of the strength of Python, right, that you can like install PyTorch and it like run stuff on CUDA and you don't have to really think too much about CUDA. But it's also an area where there's like library. Authors like PyTorch have had to invest a lot in making that experience good and all the tools do it slightly differently and people still run into problems.
Charlie:So we've been working on a bunch of specifications that we want to put forward as standards proposals and we got our UV prototype of that working like end to end, which is cool, with wheels that the PyTorch team built that have these stuff enabled for as a proof of concept. And then a UV installer as a proof of concept that can basically look at the GPU on your machine, see like, is it an NVIDIA GPU, an AMD GPU, like an Intel XPU, what version is it? And then install the right wheel without you having to really do anything. That's sort of like the vision. So we got that working end to end, which is cool, and there'll be some big.
Charlie:That's going to be part of the PyTorch 2.8 release. We're going to be part of the pie torch um 2.8 release. We're going to do some sort of like, some announcements around that it's a proof of concept. It's not really meant for users to use right now because it'll go through a ton of iteration before it gets standardized. If it ever gets standardized like it might not even ever get standardized, who knows, um, but that's kind of. I think the exciting thing of the week for us is that you can do the you know. You can uv install torch on uh. You can use uv to install torch on that branch and it like uses all these cool new things oh, wow, that's huge.
Bob:Yeah, yeah, yeah, yeah you know, like I said, it's very early.
Charlie:Like again, it may never get standardized, who knows? This is really a proof of concept and us trying to actually develop the design, um, but it's cool that it works end to end and that there's been so much coordination between all these different players in the ecosystem.
Bob:Exactly, a lot of players, a lot of complexity and definitely going to make it a lot better. Yep, hopefully, all right, cool. So yeah, ty I mean for some logical next step. Right, we have Raph the linter, we have uv the package manager, uh, taking a lot of uh pains for us away and you know, with the come with the type hints of python and being that increasingly important with python, take and fast api and my pi sometimes being slow for some time, ty was the logical next step. So, maybe for for people not yet aware of the tool and and um, yeah, maybe you can do a quick introduction and then we go into the more, some more specifics.
Charlie:Yeah, of course. So um, I, we build high performance Python tooling, um, and you know the two tools that people know us best for so far rough, which is a linter code formatter, does a bunch of code transformation, so it kind of looks at your code and tries to find problems with it and fix them for you. And then UV, which is our package manager, and really I guess since we first released Ruff I think, we've had requests to build what is now TY, which is kind of the third pillar. There it's our type checker and language server. So in Python Python has support for type ints. They're not enforced at runtime. So you can say X is an int and then assign it a string and the Python runtime will let you do that and won't complain. But you can build tooling that uses those annotations and tries to get to enforce type type safety ahead of time. And there are tools that will enforce it at runtime, like you mentioned, pydantic. You know Pydantic is a tool that will enforce those annotations at runtime for you, but it's not built into you know CPython itself. So you can build tools that basically take those annotations, look at what you're doing in the code and then try to find errors for you ahead of time. So mypy would be the most popular one. You know, if you say x has to be an integer and then you assign it a string and you run mypy over that code, right, without executing the code, just by reading it and analyzing it, it'll tell you oh, you said this has to be an integer, but you assigned a string, right. That's like sort of the basics of what the type checker does.
Charlie:Um, uh, and and really since we released rough, people have been asking us, yeah, to build a type checker. Um, because I think what they saw with rough was they were used to, you know, a certain experience. And then we released rough, which was just a very different experience for them. They saw a bunch of benefits and they were like, could you bring that same sort of like delta or that same like new experience to type checking, because it's something that a lot of people use and a lot of people want and feel that there's room for it to be improved. Um, so what we're building is it's actually kind of a few different things. So first it's a type checker like you can just run ty check over your code base and it will look at your types and try to find, identify errors and give you helpful feedback, help you, you know, avoid shipping bugs, avoid shipping regressions. So that's one thing. So if you've used my pie in the past, ty would be an alternative to my pie.
Charlie:It's also and this is like very fundamental to the design of it it's also meant to be a language server. So the language server is the thing that sits in your editor and, at least if you using um, uh, like vs code for example, uh, the language server sits in your editor and powers, kind of like, all the language associated features. So, um, you know, in your editor, if you click on a, a function, uh, you can ask to see all the usages of that function. That's powered by a language server. Um, and you can imagine that it's kind of similar ish to a type checker. It needs to be able to like look at a function, figure out where it's used. You know, maybe you import something. You want to be able to jump to that file. That the thing is imported is defined in All the. It's very similar in shape to a type checker. You need to be able to do all this sort of analysis to understand different parts of the program and how they connect. So we are.
Charlie:The most popular language server that people use is Pylance, which is the one that's. It's effectively built into VS Code. So if you've never even heard of a language server or never thought about your language server and you're using VS Code, then you're probably using Pylance. So TY is meant to be a type checker that you can use just as a standalone thing in your code base. It also is meant to be a language server, so an alternative to Pylance and something that would also work in other editors, not just VS Code. It would work. It's open source, fully permissively licensed, so you could use it in any editor.
Charlie:Um, uh, uh, but the the intent is really that we want to build this single tool that can serve both of those use cases, um, and so you can run, you know, the same type checking on the command line and ci as you do in your editor, that you can get this like super fast, super rich experience. Uh, that you know. I mean, hopefully it's very good, right, I mean it'll take us some time to get as good as we want it to get, but the goal is that we're building kind of a single tool that can analyze your Python code, use all the types and give you really good feedback and help you find errors. And, in particular, you know a couple of things that we're trying to do. One we want this to be able to scale to very large projects. Um, because the nature of our tooling is uh.
Charlie:Performance, I think, is just one of many things we're trying to do, but it is uh sort of. It is always a piece, and we spend a lot of time, especially with uh, with big companies that have very large projects. And a thing that we just constantly hear is the type checkers are sort of prohibitively slow on their project and or the language servers also can't scale to their projects. Like, at some point they get to a scale where the language server just can't index all the information in the code base and they can't like jump to definition stops working. So you know, one thing we're trying to do is we want it to be very fast. Um, ideally the fastest type checker out there. Um, you know, hopefully by a lot uh is the goal at least. Um, we, uh. We also want it to be uh you know this is more framed Uh, this is not necessarily exclusively to to newer users, but we also want it to be. You know this is more framed. This is not necessarily exclusively to newer users, but we also want it to be ideally, like more helpful than any other type checker.
Charlie:So another big focus for us has been like diagnostics and error messages and just thinking a lot about how we explain what's going on, like why this is a problem and how you might fix it.
Charlie:So we've invested a lot to and sort of that would be called like our diagnostic system, like how we report errors back to you and the kinds of things we can do. So, for example, our diagnostic system like it can pull in and show you context from multiple files, which is pretty cool. So like if you call a function and you pass in arguments of the wrong type, when we show you the error, we'll show you both like the function call and the function definition in your terminal, which is pretty different than other type checkers in the ecosystem and it sounds like a small thing, but our goal is to build kind of this really rich system to pull in to give you really helpful error messages and pull in like really important context. So you know, just as an example, like we're trying to build something that's both really helpful for, uh, all users and something that can scale to projects that you know right now have a lot of problems with type checking yeah, a lot to unpack there, but uh, just to go over a couple of things.
Bob:So I guess the uh nicer error messages are more informative. Uh, you know, we have a double win right, because it's not only better for the human developers, but it can also help ai better, or ai agents, right, is that? I hope so, yeah yeah, it is.
Charlie:I mean, I think like, yeah, like, honestly, it's probably something we would have had as a goal anyway, just because, like, it's also something we've thought about in law. In uv, like in uv, we're always like how do we give better error messages? It's probably something we would have had as a goal anyway, just because it's also something we've thought about in law. And UV, in UV, we're always like how do we give better error messages? It's a big thing that we think give more, better context, more information on how you can solve errors. Um, you know, one of my favorite like for models basically to help them figure out. Because, because, ultimately, like, if you're running an agent, like if you're using cloud code or something similar, like the thing that really matters is, like you have to create a good feedback loop. So, like, a type checker is a big part of that, because you know you want the model to be able to get feedback on, like whether the things it's doing are correct, like is the code working, and like tests are one form of that type checking and other static analysis tools are another, and so, giving them good diagnostics, helping them understand, like, what the problem is and potentially, how to fix it, I think will be a big win. You know, I think a really cool example here, which I mean I didn't have went to any of this so I can. I feel very good bragging about it or very comfortable bragging about it.
Charlie:But you know there are like different versions of Python change the standard library, so you know, at different points in time maybe they introduce new standard library modules. And one thing that TY will try to do is if you say like, okay, my program, it supports Python 3.10 and later, but somewhere in the program you try to import from the standard library like a module that only exists in Python 3.13, and later TY should tell you well, that's actually like a module that only exists in Python 3.13. And later ty should tell you oh, that's actually like a problem because you're saying that your program is supposed to run on Python 3.10. But like, if you try to import this new module that doesn't exist in Python 3.10, your program will error. And when we do that we don't just tell you that that's a problem, we also tell you like, why we think that your program is supposed to run on python 3.10. Like we'll tell you oh, in this file you said my support is python version is like 3.10 and later, like specifically like this file on this line. So it's not just telling you like what the problem is, but it's also giving you like the context on helping you understand, like why we made that deduction and like what you could change, like oh, maybe you should go in there and like update, like raise your minimum supported python version and like blah, blah.
Charlie:So trying to pull in like really helpful, actionable feedback, I I just think it goes a really long way and it's something that we've also picked up from. Uh, you know, we build all of our tooling in rust and this has been a central tenant of rust. I mean, I don't know for for for long before I started using the language, but the, the rust compiler, and just like rust tooling tends to have very, very good error messages and they invest in it a lot and it's like very much a first class thing, um, and so that that's part of how we draw inspiration for what we want to do. It's like that should be like the bar for how good the error messages should be. We want people to have these like oh my gosh. Moments, like they do when they're using Rust.
Julian:A quick break from the episode to talk about a product that we've had going for years now. This is the PyBytes platform. Bob, what's it all about?
Bob:Now with AI. I think there's a bit of a sentiment that we're eroding our skills because AI writes so much code for us. But a bit of a sentiment that we're eroding our skills because AI writes so much code for us. But actually I went back to the platform the other day, solved 10 bytes and I'm still secure of my skills because it's good to be limited in your resources. You really have to write the code. It really makes you think about the code. It's really helpful.
Julian:Definitely helpful, as long as you don't use AI to solve the problems. If you do, you're just cheating, but in reality, this is an amazing tool to help you keep fresh with Python, keep your skills strong, keep you sharp so that when you are on a live stream, like Bob over here, you can solve exercises live with however many people watching you code at the exact same time. So please check out pybytesplatformcom. It is the coding platform that beats all other coding platforms and will keep you sharper than you could ever have imagined. Check it out now, pybytesplatformcom. And back to the episode.
Bob:Yeah, yeah, indeed. If you do cargo run and riding any rust, you quickly realize how you need to.
Charlie:Yeah, yeah.
Charlie:We also stole a lot of good ideas too. Yeah, I think like yeah, I mean UV run. That's kind of like the central UV command now, and you know the thing it does is like creates the virtual environment, locks your dependencies, installs them and runs the command and like it can skip those things if everything's already in the right state. But the thing that we really wanted, which we like from cargo, was like we didn't want to necessarily have an explicit install step, like things shouldn't get out of sync, you shouldn't have to think, oh, I just added this dependency to my PI project tombo, now I need to run UV sync and then UV run and blah, blah. Like you should just, you should just keep everything. You tell us what your requirements are and then we get everything into the right state.
Charlie:When you want to run something and that's something we kind of took from um, or at least it's an experience that you get in cargo like in rust, you just like change stuff and do cargo run and like it. You know it just like locks and compiles and then like runs the code and like you don't think about okay, now I need to run npm, install or whatever um like there isn't there isn't this explicit step, it just works everybody talks about the, the speed, and, yeah, we have now one tool for all, which are, of course, all amazing.
Bob:But, uh, one of the things that really struck me with uv is like it's this whole chain of things and you just don't have to think like, oh, I need to do this previous step. No, if, if UV sees that you're missing a step, for example, or no, not a virtual environment, it goes out and create one. Right, so it's, yeah, it's. It's really a pleasant developer experience.
Charlie:And maybe just like say one thing about that in terms of, like our philosophy, um like, yes, I think speed is definitely a big part of what we do. I think it's great for getting people interested too, but we're trying to solve ideally bigger problems than just speed. We didn't want UV to just be a faster pip, it's supposed to be a very and we have this pip-compatible interface, which I think is great, and a lot of people use it. It's very popular. But, like, we're also trying to solve other problems.
Charlie:But one of the things that I think sometimes, um or that I see as a big advantage, is sometimes speed like lets you build things that you otherwise couldn't build. And it's not about the speed. Like the fact that we do the like lock your and resolve your dependencies, install them, create the environment, all as part of the command. Like you couldn't do that if each, if each of those steps took five minutes, right, just as a thought experiment. Um, so like the fact that we build something really fast and focus on performance actually lets us like build different, slightly different experiences, and I I think I think the same will be true of ty. I hope um like there's. There are some, you know interesting things we want to do. That will require a lot of analysis, and I think focusing on performance will help enable some of those things that we otherwise might have felt prohibitive.
Bob:Yeah, my evolution with Ruff went from I use it with pre-commit, but then of course you have to git commit again, right, and now, because it's so fast, I just have a key map to control S which I use in Vim for save, and because it's so fast, you can do it, I can just run a rough every save, which is ridiculous.
Bob:But, yeah, if that tool would only take one or two seconds, you're already not doing that, right? So, yeah, it's again really nice. But yeah, going back to the speed and TY. So what were some of the trade-offs you faced when optimizing TY versus MyPy? Being exhaustive, because, yeah, mypy can be quite slow, but then of course, it must be very complete as well. Right, and you start building this tool. Yeah, how do you balance that?
Charlie:Yeah, yeah, I mean, I think I don't Maybe I'm naive I don't think they necessarily have to be trade-offs. I mean I think we, well, you know, before I guess, before I get much deeper like ty is definitely incomplete, um, and like listeners should know that uh, like we market it as not ready for production. Um, there are teams that are using it in production, um, which which is great, you know, which is great, you know which is great. We get a lot of feedback. It's helpful, um, but, uh, some people will probably try it and it just won't work on their code base. Or some people will try it and it will miss obvious things, and that's just like known. That's why we haven't done a beta release yet. Um, for example, like I mean, this might be stale by the time this episode comes out, but like we don't really support like typed dicts right now. We just haven't implemented that and so we have, like the infrastructure to do it, but it's like on our list of things that we need to get through with, among us a bunch of other stuff. So, you know, if your code base uses typed dicts, um, like it'll probably behave like reasonably, but it'll like miss a bunch of errors that like it otherwise should probably be guarding against. And so just you know, just as an example, like we're definitely not done in terms of implementing the whole spec of things we want to implement Um, but a lot of like the optimizing for speed.
Charlie:I think there's kind of two parts. The first is, uh, kind of like the same to uh, the same set of considerations that we had, for I think rough would be a little bit of a closer analog than than UV, but you know one writing it in rust, relying on a lot of the shared infrastructure that we have with rough, that we've already optimized, like our parser, like the thing that takes code and turns it into the syntax tree that we can analyze. That's all shared, shared with rough, and we've tried to share as much of that as possible. Um, you know thinking about things like data layout, efficiency, like how do we make our objects smaller, and like more efficient to allocate and deallocate the kinds of things that you can think about when you're working in a language like rust or c++ or whatever else. So one piece is just kind of similar to rough, like how do we write really good, optimal, optimized rust code for dealing with text and syntax trees and all that kind of stuff.
Charlie:The other piece which is unique is um, uh, every, what I would call like incrementality, um, and this comes from the desire to build a language server. So, uh, uh, like I said earlier, like a language server and a type checker. They have some similarities but but they're also pretty different. Like a type checker, you kind of sit down at your machine, you're in your terminal and you run like my pie, you know my pie, pat the file or whatever, and uh, you know, typically what will happen is that command like ignore, like caching for a second, like imagine you go and sit down and run that for the first time It'll analyze the entire program, like all the different files, like all your dependencies, and then like come up with, like you know, a set of errors.
Charlie:That's really different than what you want from a language server because, like in a language server, imagine you have like a really big project and you open up like one isolated file in your editor maybe it doesn't even import anything like in order to give the user feedback about that file. You don't want to have to analyze like the entire program, all of your dependencies, all of that um, like, you want to be able to just start at that file, analyze it and then pull in whatever else you need. Maybe it imports like one other file. Okay, we'll like go read that file too. But like try to do the minimum amount of work possible to give the user feedback, because they're in an editor. In an editor, like context is really quick. Like you're opening a file, you want to get feedback quickly. You don't want to wait like five minutes for the type checker to analyze the whole program.
Charlie:So part of it is like a language server has to be very lazy. Like you just want to do the minimum work necessary as, uh, these sort of requests come in. And the other part is you want to be very incremental. Like imagine if you're in a huge project and you're working on one file and it just imports one other file, so like it's really small, but the project is huge, and then you change something somewhere else in the code base that's totally unrelated. Like you don't want your editor to have to then completely reanalyze like the whole project and all of your dependencies, because nothing it didn't affect what you're working on at all.
Charlie:And so that is what we think of as incrementality, like if we already understand the state of the program and you change something that doesn't affect what you're looking at, we should only have to redo work that is impacted by what you change. So, um, uh, you know, basically we come up with the state of the world, which is like analyzing the program, and then, when you change something in some file somewhere, we can actually sort of look at the graph of what does that affect and then just recompute the parts of the program that are affected by it, which is like super powerful, because it means, like when you're working in an editor, uh, and you change something in one file that doesn't affect anything else, we can really really quickly recompute like okay, what's different now? Like like, where are the new errors? What errors were resolved? Like we don't have to go, and it's not like we have to run my pie over your full code base every single time you change a file. Like that just wouldn't work Right.
Charlie:So, um, so one piece, like I said, of performance is like just trying to write a fast rust program. The other is this focus on, like laziness and incrementality. Um, that comes from building a language server, um, and we made some decisions really early on that, basically that that was going to be a goal like that. We wanted incrementality to be a goal, and there's a lot of different levels to it. You could think of it as like file level, like whenever you change a file, recompute everything that's touched by that file. But you could get like even more granular. You could think of it as like function level, like if you change an annotation that's local to a function, like you should only need to recompute that function, and so there's lots of different ways to approach it.
Charlie:We we ended up building a top of framework, a rust framework called salsa, which is also used in rust analyzer, which is rust, the most popular rust language server. Um, we kind of like looked and we were like, okay, we need all these properties around incrementality and we could either like build our own custom thing or like use salsa, but we're going to have to like contribute to it significantly and really learn how to use it, cause there's like a lot of things that we need to change, and we ended up doing that. So we've been contributing. We basically have like one person full-time kind of working on salsa, trying to make different improvements to it, and and working on salsa trying to make different improvements to it um and and sort of help modify it to make to support some of the things that we need to support Um.
Charlie:But the net effect is like when we're writing code in TY we're often thinking in terms of like what, what affects what else, um, like what's a dependency of what else, um, and kind of for free I for free is a little ridiculous Cause like we do have to put in a lot of work to like make this work. But like, basically, if we stay within the bounds of how that frameworks also works, where we think about things in terms of what affects what else, then we get a lot of this incrementality out of the box. Um, like we can very quickly recompute some parts of the program which is just very different from any other Python type checker. Like that you know that. Like no one I don't know. I think it's safe to say that we will have the most advanced like incrementality model of any Python type checker. And that's been a big part of the design. And again that comes from these desires of like we want to build a great type checker. And part of the design and again that comes from these desires of like we want to build a great type checker and a great language server, and they have things that are in common but they also have like very different requirements and if you don't think about both of those from the start, you end up in a little bit of trouble.
Charlie:Exactly, rough would be kind of a counterexample of this where, like when I designed ROUGH, I wasn't thinking about the language server at all, I was just thinking about like using it from the command line.
Charlie:So nothing in rough is like follows this incrementality or like laziness model, and rough is way simpler. Like rough only looks at what each looks at each file individually, and that's where a lot of the performance comes from. And so if you change a file, we just analyze that file. But it's because rough doesn't know anything about the connections between files and that really limits the kinds of inferences we can make, the kinds of things we can do. Like we don't really understand. Like if you import from a module and you try to import a bunch of things that don't exist, rough doesn't know anything about that because it doesn't know like what file a exports the file it can import. File a exports the file b can import um. So I think that's. I'm just trying to say like from the start, we had a very different design goal and took a really different approach to the design, because we want to be able to work in all these different contexts yeah, fascinating, I'll unpack again.
Bob:So, yeah, sorry, no, no, that's cool. Um, so, definitely a tool where you need to get the design right from the start, right Heavily designed on the language server. So I guess that was something you were seeing in the type checking space, or where did that knowledge or inspiration come from?
Charlie:Which part Like that we wanted to build a language server or.
Bob:And that it's so rooted in that design.
Charlie:Cause you have to I'm like you have to kind of come up with a design right Like this was really like we got the right design from the start, and and not that it's then easy, of course not, but that played a big role right, yeah, it's played role and like um, we definitely like paid a big tax for it, like we like the first few months of development, um, but I I mean not not my judgment, this is like what I hear from from the team really but they're like it went a lot slower than expected because we we decided to basically invest up front in a lot of this like core infrastructure. Like, okay, we want to get the architecture right, we want to be incremental, we want to have a great diagnostic system, like all those things were kind of like core infrastructure that we just invested a lot in upfront and now we're at the phase where, uh, there are still like a few like big, hard outstanding problems that we're solving but, at the same time, a lot of the work that's left is like I don't want to minimize how hard it is, but like there's a lot of sort of like type system feature work. That's like building on the infrastructure that we've laid and that's kind of like what we're getting like type dicts would be an example, um, or like david added, like enum support this week. That was like another thing. Right, it's like that's kind of like leveraging the infrastructure to like build out all these different features that exist in the type system. So we've kind of switched more into that mode. Um, you know still plenty to do, but like it's a little bit more of we built all this infrastructure and now we get to like use it, uh, to try and uh support everything we need to support a lot of, I think, a lot of my awareness about, about the type checker versus language server thing.
Charlie:Well, the desire to build it, I think, came from talking to a lot of companies that had issues with existing language servers and you know a lot of different problems too, like there were also companies that like were, um, you can't like pylance, for example. Um has a like proprietary license on it, so you actually can't use it outside VS code. And now there's all these like VS code forks, um, and there's slightly more diversity in editor now than there was a few years ago. So, like, in addition to VS code, you have like cursor and windsurf, right, and then, uh, it's also like Zed is becoming quite popular, right, and none of those can really use PyLance. So they all come up with slightly different solutions around the language server. And so I was seeing, like talking to big companies where, like, the existing language servers weren't scaling to what they needed, and then also seeing the sort of like diversity in editor and talking to the people who work on those editors and them being like we of want like a better python language server, and so I think for us it just made a lot of sense to focus on that from the start.
Charlie:And then I think a lot of my understanding of like how the problems are different actually came from, um, this guy, um alex kladov, who goes by matt clad online, who was uh I don't want to get the history wrong, I'll just say like the main contributor to rust analyzer in the early days.
Charlie:Um, uh, he did like a this youtube series, uh, that was called like building rust analyzer or like inside rust analyzer or something, and it's a series. It's like it's like like hour plus long videos where he talks about, like in a lot of detail, the architecture of rust analyzer. And I watched this. I remember I watching this, like after my, my first child was born, so it was probably like two, two and a half years ago. Um, but, uh, I remember watching a lot of those and just thinking, oh, wow, okay, like he's right, like cause he hammers home a lot of these things which is like it's very different, like you need to think about like X and Y and Z from the start, and so I a lot of my like thinking about that was influenced by that series, which is um very good, if you like that kind of thing quick break for a note of our sponsor this week, which is five bites that's us, pybytes, pybytes that's us I'm here, Bob.
Bob:What are we talking about this week? Well, we have a new coaching program PDC or PyBytes Developer Cohort. We thought it was never going to happen because we have been doing one-to-one for five years, but now we can do group coaching as well. We're going to build a real-world app six weeks in an exciting cohort. We're going to learn with one of our PyBytes coaches the whole journey, but also work together and learn together. And yeah, no more tutorial paralysis. Build, build, build.
Julian:It's wonderful. It's not something you want to miss out on, so please check out the link below, pybytescoachingcom. This is a program that bridges real building with a cohort, environment learning with other people, building with engineers. It's a wonderful thing. Check it out. Now, pybytescoachingcom, and back to the episode.
Bob:So how do you stay aligned with the fast-evolving Python type system? There are so many things being added and it's crazy, right? So how do you keep up with that while still? Because you ship a lot and fast, right, but the ecosystem also changed very fast, so how do you keep them in sync? Yeah, yeah From the design we've spoken about, which is now nicely extensible, it seems, but still it's a challenge, right?
Charlie:Yeah, I mean the Python type system is complex and we're still trying to work through all the existing features In some ways. Fortunately, it actually hasn't been changing that quickly over the time that we've been working on TY. Like pep695, which was a big change to the type system it added the type keyword, like type aliases and also generics in various places and all this fancy stuff that actually came before we started working on ty and that was probably the last like big change. I mean, there are still lots of changes that come in every release, but, like, thankfully it hasn't changed that much. I I'm sure it will continue to change.
Charlie:Um, but uh, you know, for us, like a lot of it's about prioritization. Like we've tried to do things earlier that we thought would have a big impact on, like, the core design, and sometimes we got that right, sometimes we got that wrong. But, like you know, we're learning and, uh, we also look quite a bit at like in terms of prioritization, sort of like how frequently things are used and how common they are. Um, we in rough we invested relatively early on in this sort of like what we call, like, the ecosystem report. So, like, every time you put up a pull request on rough, run rough over a selected list of projects and we basically run it before and after and we tell you, like the diff, like okay, you fix a bug, and now there's like four fewer diagnostics in, like sci-pi or whatever, and like here's what they. We actually show you the difference. It's like super, super helpful. Um, we've done a lot of that in TY also. Um, there's a project called my pie primer which is was developed to do this kind of thing. In my pie Um, we run TY on all the projects in my pie primer um on every commit, so it's like over a hundred projects.
Charlie:And then we get the diff of like basically the diff of the output, and like some sense of did we remove a bunch of diagnostics that were false positives? Or like did we add a bunch of false positives, or like how did things change? Um. So we'll kind of like look at that, uh, on an ongoing basis of like are we doing the right things? And then, at various points in time, we'll like look at the primary output and try to categorize things that are occurring and use that as a way to prioritize. Like okay, we have lots of false positives related to like enums, um, or I don't know, like david recently added support for like exhaustiveness checking and match statements, so like, if a match python match statement covers all the possible cases, like, we should know that basically and incorporate that into our analysis and, like that, removed a bunch of errors from from my PI primer.
Charlie:So, um, you know, a lot of what we do for this kind of tooling is basically try to run it at scale on lots of different Python code and then create ways to make sense of directionally of like the changes that we're making. Um. But yeah, I think the short answer is thankfully the type system has not changed that much in the time that we've been working on ty. There's still a lot that we need to do. Most of the hard questions are really around prioritization, around the order in which we solve certain things, um, but we try to solve that directionally by looking at lots of python projects at scale and seeing, like, where we can have the biggest impact for bringing things into alignment.
Bob:Yeah, wow, time flies when you're in fun. So I think it's time for two more questions. So let's see what would be interesting. Let me do one, and then I'll give you an opportunity to bridge any gaps. We haven't spoken about you the opportunity to, uh, to bridge any gaps. We haven't spoken about um. So now I have a hard time choosing the best one. Well, maybe you said the the rough one, rough tool. So, first of all, I find it fascinating that um design carries over from tool to tool, right, um, that's, I mean again, ty, ty, super complex project, but you're leveraging a lot of things from previous projects, right. So two things here. Right, when I saw the docs for TY, you have this whole rule system, right, and it kind of mirrors how that's implemented in ROUGH, right? So would you say these are clear influences from tool after tool that shine through these are clear influences from tool after tool.
Charlie:That's that's uh shine through. Yeah, I mean, I think in a lot of ways we see TY or maybe to some degree we see TY as an opportunity to get some things right that we think we got wrong in rough. I mean, like in rough, uh, you know, the main things that are shared are like the parser and the AST and then some other some other things. Um, there are a lot of things about roughs rule system that we don't like and that we want to change. Um, uh, and maybe some of those things are reflected in uh, ty. For example, we really want rough to move towards human readable rule names and this is something that people ask for all the time. Like in rough, every rule has like a six or roughly like a six digit code, um, and but internally they all have human readable names, like in our code base, and like we want to make those like first class um and so from in ty, we like did that from the start? We're like okay, all the rules will have like human readable names, um and etc. Etc. So in some ways we're trying to get, I think, some things right. Um, that we feel like we got wrong and rough, and it's not that those won't be corrected and rough, it's just that it's harder to change them. And if we do change something fundamental, like all the rule identifiers or like how all the rules are categorized, we kind of want to do that once and get it right. So we put a lot of pressure on ourselves to make that change. In rough it's just harder when you have a lot of users, whereas ty is new and like we can make some slightly different decisions. Um, I guess, relatedly, there are still some things that we're trying to like our focus has really been on like let's build ty and like get it into a state that teams can use it in production and like that that's our priority. Uh, but there are, you know, some interesting questions, like longer term between, in terms of what the relationship between rough and ty should be, because there's some overlap between what they do. I mean, they're slightly different but there's some overlap.
Charlie:Um, you know it's it's not like rough, in quotes, incorporates a lot of knowledge, a lot of opinions, right, and depending on the rules you enable. Like a lot of opinions and a lot of knowledge, a lot of opinions, right, and depending on the rules you enable, like a lot of opinions and a lot of information about python idioms, um, sometimes even information about, like specific libraries, um, a lot of that's outside of the scope of a type checker. Like the type checker's job is to like use the type system to give you information, uh, and find errors. But there's some overlap right like an unused import. In theory that could be in like either one or like a variable that's like defined but never used. Like some type checkers will catch that and not just a linter. So you know there's some. First of all, there's like kind of some blur, some blurring of like what's responsible for what.
Charlie:And the other piece is like ultimately, we don't just want to be able to build a type checker, we want to be able to build like a type aware linter. Like imagine if rough, for example, had access to all the type information that ty is aggregating. Like we have a lot of rules in rough that would really benefit from that. Like we have rules that are only supposed to fire when something is a dictionary. Like if you call some method and it's a dictionary and like the arguments are, there's like maybe a better way to do something, like then we fire, but like rough doesn't really have a good way to know if something is a dictionary um, because it doesn't. It's not a type checker, it doesn't do like full type inference. So you know, we kind of use like heuristics to figure out like, oh, this is probably a dictionary, so like we can probably trigger this rule.
Charlie:But imagine if rough could actually like know that right, like like you actually figure out, is something a dictionary um. So in the broader vision of things, like we do want to have a type checker language server, but we also want to have this like type aware linting experience and um, you know, we're still sort of figuring out the best way to do that, whether it's like rough uses TY as library or like they become one tool, like I don't know. We sort of we have a lot of opinions about that as a team, but like we kind of intentionally not decided on that right now, cause our focus is really on like shipping TY and we know that's something we want to do, no matter the, you know the, the, the sort of like longer term outcome, but but but I guess, just so you know your people are aware like we do think a lot about that and ultimately what we want is for rough or some sort of type aware linter to exist in addition to the actual type checking that we do.
Bob:Yeah, interesting, because there are now two standalone tools but they're actually in the same repo, right?
Charlie:Yes, or TY is a submodule or something like that, right? No, yeah, they're developed in the same repo, but TY is released from a separate repo. That pulls it in as a submodule. Sort of silly. But it kind of just makes things easier because GitHub releases stay separate. For example, TY's releases are in the TY repo and Ruff's release is in the Ruff repo and the issues. We keep the issues separate and all that kind of stuff. But because they share so much code, we actually develop them both in the rough repo yeah, maybe an implementation detail as well.
Bob:Um so yeah, maybe as a final question if it's not answered enough. But people, people, I think, should I use this? Should I wait till it's production ready, like I'm using it, like I find it already, you know, very useful. But again.
Charlie:We do hear that quite a bit maybe to that concern.
Bob:Uh, yeah, sure.
Charlie:Yeah, I mean, it's like I said, like we advertise it as not production ready and you know, one of the reasons we do that is because we know, uh, well, first of all, we know that, um, some people will try it and it basically just won't work on their code base and like we're not going to call something production ready until we feel pretty confident that won't happen. Um, but also we kind of know, like we kind of know like some people are going to try it anyway and like that's honestly really fine and um, it's a little bit by design because, like we get a lot of feedback that way, um, and it's helpful, but but the feedback that we get I guess I shouldn't like say this out loud because it maybe ruins it but like the feedback we get tends to be from this kind of like early adopters who are willing to use a tool that they know is in production ready and so like it's typically pretty helpful and like those users are quite engaged and they know they're kind of opting into like helping us build the thing, not just using it in some very subtle sense. So like, definitely fine with people using it, but we just don't want to put the same guarantees on it, because we know that there are things that aren't supported. Just don't want to put the same guarantees on it because we know that there are things that aren't supported. Um, and so you know. I think a nice thing about it is like you could use just the lsp, for example, like you could install the extension and use the lsp and like that wouldn't interfere with, like your core type checking, but it's like something that you could. You could see the diagnostics in your editor and like see the kinds of things it's picking up. Um you could use it like just in while you're developing locally um as like a faster type checker to get like some feedback before you run. Maybe for now you're using my pie or something like maybe you're running my pie in ci, but like locally you're kind of like using ty to sell as you develop or iterate because it's quicker. Um, we've, you know I.
Charlie:I think a nice thing about adoption, especially in like real world code bases, is we really try. It's like this is very different. The degree to which we're doing this is actually very different from other type checkers, but we try. Our design philosophy is that we try to minimize false positives, especially on untyped code, and this is, in part, to make it easier for people to adopt a type checker in untyped code bases. There's sort of a lot I could say about this.
Charlie:There's something called like the gradual guarantee, which is like this idea that the type checker shouldn't really be like making assumptions about your intent, that calls false positives, that require you to add annotations to tell it that it was wrong and so like an example. An example here would be if you like a class attribute in python and you do like x equals one, no type annotation. But you just do like x equals one, other type checkers will typically assume that means the field can only be an integer. We actually don't really do that, um, because maybe it could be something else, right? Maybe it could be not. Maybe later in the program you assign it none or something. Um, other type checkers will tell you that's an error. Yeah Well, other type checkers will tell you that's an error because they're like. Checkers will tell you that's an error because they're like oh hey, you assigned one to this, so I assumed it's an integer and then you assigned a none to it.
Charlie:We actually don't do that like um, and that's because of this idea of like the gradual guarantee that, like in untyped code, you shouldn't have to like go add annotations to like fix false positives. That that's the thing that we're trying to avoid. Um now, if you like, maybe we know that that um, instead what we say is x is either like it's either like an int or it's kind of like unknown and that might sound like we can't really do anything with it. But but it's not true. Like if you later try to do something with x um, that would be an error when called on an integer. We can still give you feedback for that. So like there's still a lot of safety and like help that we can give people.
Charlie:But the the goal is to minimize the kind of false positives that lead to kind of like fighting the type checker, especially on untyped code. So like it's very much an intentional goal that like we want to make. Uh, you know again it's not just about performance Like we're actually trying to build a pretty different experience and like this is one of the ways that we're um just like the fundamental design, how the tool works, is really different Um, so anyway that uh Carl Meyer on our team is really like the sort of like a mastermind behind a lot of that Um, but uh, uh, I I think it's like a really cool direction to be pushing in and, um, hopefully we'll make python typing, uh like, more useful and also easier to adopt, um, especially for code bases that aren't heavily typed yeah, very interesting.
Bob:Okay, I will skip the normal book reading question. Uh, yeah, so I'll give you a chance to I don't know give one final shout out. Or maybe you want to say something what's next for Astral? What's coming? I mean, you're?
Charlie:I mean we're doing a lot of stuff, yeah, I think, yeah, yeah, yeah, I don't know, I think I'll just like I just want to shout out the team because, like with TY, I just want to shout out the team because, like with TY, I've contributed to it a little bit, but it's kind of the first time that I'm like really not working on a new tool that we're building like day to day and like Carl has really like Carl and our team and and Mika if you I don't know if you interact with our, with the team online you'll like see some of these names. They've been doing a great job of kind of like steering the project on the type tracker and the LSP. Um, and we have a big, big group of people working on it that are just doing great work. Um, and it's it's been so cool just to see them like to see this thing come to life. So, um, yeah, I'm just really proud of all the work the team has done and like all the work they're all I'm sure continue to do as we get this ready for people.
Charlie:Um, but if you feel like you're an ambitious, motivated user, you know, feel free to give it a try. Um, and uh, you know we're targeting a beta release later this year. Um and the, the. The goal of that beta release is, like you know, you should be able to try it in production and like, hopefully most teams should be able to migrate over. So that's the goal for us right now is kind of working towards that beta release over the next few months.
Bob:Yeah, very easy to get started. Uvx DY. Thanks Charlie for hopping on today. Nice, in-depth discussion. Hope our PyBytes audience got the inner workings more clarity on that and they will check it out. Yeah, thanks for all you do in the space, definitely making our tooling so much nicer.
Charlie:Yeah, thanks so much for having me on again. It was a blast. I look forward to next time forward to next time.
Julian:Hey everyone, thanks for tuning into the PyBytes podcast. I really hope you enjoyed it. A quick message from me and Bob before you go to get the most out of your experience with PyBytes, including learning more Python, engaging with other developers, learning about our guests, discussing these podcast episodes, and much, much more Please join our community at pybytescircleso. The link is on the screen if you're watching this on YouTube and it's in the show notes for everyone else. When you join, make sure you introduce yourself, engage with myself and Bob and the many other developers in the community. It's one of the greatest things you can do to expand your knowledge and reach and network as a Python developer. We'll see you in the next episode and we will see you in the community.