Monitor performance issues & errors in your code

#453: uv - The Next Evolution in Python Packages? Transcript

Recorded on Tuesday, Mar 12, 2024.

00:00 Have you ever waited around for a pip to do its thing while installing packages or syncing virtual environments

00:06 or even through some higher level tools such as pip tools?

00:09 Then you'll be very excited to hear about what just got announced from Astral,

00:14 a pip compatible CLI tool called UV.

00:18 It's like pip, but a hundred times faster.

00:20 Charlie Marsh from Ruff fame and the founder of Astral is here to dive in.

00:24 Let's go.

00:26 This is "Talk Python to Me" episode 453 recorded March 12th, 2024.

00:31 (upbeat music)

00:34 Welcome to "Talk Python to Me" a weekly podcast on Python.

00:49 This is your host, Michael Kennedy.

00:51 Follow me on Mastodon where I'm @mkennedy and follow the podcast using @talkpython

00:56 both on mastodon.org.

00:59 Keep up with the show and listen to over seven years of past episodes at talkpython.fm.

01:04 We've started streaming most of our episodes live on YouTube.

01:07 Subscribe to our YouTube channel over at talkpython.fm/youtube to get notified about upcoming shows

01:13 and be part of that episode.

01:15 This episode is sponsored by Neo4j.

01:18 It's time to stop asking relational databases to do more than they were made for

01:23 and simplify complex data models with graphs.

01:26 Check out the sample FastAPI project and see what Neo4j native graph database can do for you.

01:33 Find out more at talkpython.fm/neo4j.

01:38 And it's also brought to you by us over at Talk Python Training.

01:42 Did you know that we have over 250 hours of Python courses?

01:47 Yeah, that's right.

01:48 Check them out at talkpython.fm/courses.

01:52 Hey all, I have a quick announcement before we jump into the conversation with Charlie

01:55 and sticking with the theme of the episode, I'll keep it quick.

01:58 Over at Talk Python, we just released a new free course.

02:01 It's all about working with audio in Python, converting it to text, applying all sorts of AI awesome sauce and more.

02:08 We end up with a dynamic web app that lets you have a ChatGPT style Q&A with a podcast, guests and hosts

02:16 starting from just the RSS feed.

02:19 It's really mind blowing.

02:20 As a sweet bonus, the course shows you a bunch of hands-on examples of FastAPI,

02:25 HTMX, Beanie, MongoDB and more.

02:28 I hope you love it.

02:29 Give it a look as it is 100% free, no strings attached.

02:33 The link is on the episode page, in your podcast player show notes and at talkpython.fm/courses.

02:38 Hey Charlie.

02:41 - Hey.

02:42 - Welcome.

02:43 - Yeah, thanks so much for having me back on the show.

02:44 I really appreciate it.

02:45 - Yes, it's really great to have you back on the show.

02:48 You and your team are doing awesome work these days and making a big dent in Python.

02:53 - Thank you, thank you.

02:55 Hopefully a good dent, I guess.

02:56 (laughing)

02:58 - Yeah, I guess you could make a good dent or a bad dent.

03:00 But no, I meant that in a good way.

03:02 Definitely in a good way.

03:03 - I appreciate it.

03:04 - Yeah, yeah, I think excellent work.

03:05 It's really, it's kind of surprising how some of these tools just come in

03:10 and just catch fire in a way.

03:12 I don't know how you felt about it, but it seemed more than I would have expected.

03:16 I mean, I did not expect your things to be popular, but they became really popular really quickly.

03:22 (laughing)

03:23 - Yeah, yeah, I mean, it was different with Ruff and with UV.

03:26 This sort of context around it has been pretty different because with Ruff, like when I started working on Ruff,

03:33 no one knew who I was or had any reason to care about what I was doing.

03:37 And the project just grew over time.

03:41 And then I knew that when we were working on UV, there would just be a lot more of an expectation

03:46 around like anything we build.

03:47 - Yeah, the spotlight was already shining, right?

03:49 - A little bit, yeah, yeah.

03:51 And that's awesome 'cause it means our stuff gets traction.

03:53 Also, it comes with a lot of responsibility.

03:55 It means anything we release, we're kind of committed to maintaining.

03:59 So like, it's been very interesting, like this kind of release cadence versus what happened with Ruff.

04:07 - Well, you have more people behind the scenes helping you out, right?

04:11 - I do, yeah, thankfully.

04:12 - Yeah, tell us, maybe that's a good place to just kick off our conversation is,

04:18 you know, we're talking a bit about Ruff for everyone, but in Ruff was the thing that really launched all of this,

04:24 but you started a company, Astral, got some funding behind it, building awesome tools.

04:30 Yeah, just give people the broad view of your world these days.

04:33 - Yeah, totally.

04:34 So yeah, I started, this all started when I released Ruff probably like a year and a half ago, maybe at this point.

04:43 And at that point it was really not just a side project for me, but very much an exploratory project.

04:50 Like I was kind of curious about building faster Python tooling really, and curious about getting better at Rust

04:57 and all this stuff.

04:58 And Ruff, when I released it, it's, you know, it was a lint or it is a linter,

05:05 but it kind of brings a lot of different tools together.

05:07 So if you're familiar with like Flake 8 or Pylint, but also Black, Ruff is designed to kind of bundle

05:15 all those tools together.

05:17 So it can detect problems with your code, it can fix them automatically, it can reformat your code.

05:23 So often when we see people like adopting Ruff, they're replacing like 20 or 30 tools with Ruff.

05:29 And, you know, it has, there's a bunch of nice things about it, but ultimately it's very, very fast

05:34 and hopefully a lot simpler for users.

05:37 - Yeah. - But, go ahead.

05:39 - I was gonna say, it's really nice that it's just, one tool that brings that all together.

05:44 You know, it's not a patch where, well, here's how we use isort, and here's how we use Flake 8,

05:48 and here's how we use this, and here's how we use that, you know?

05:50 - Right, I think isort's a really good example, because instead of having and isort's a great tool,

05:55 but instead of having a separate tool to do your import sorting, Ruff frames import sorting as just a lint rule.

06:01 And so you don't have to learn a bunch of different tools and figure out how to sort of merge them together.

06:06 And, you know, Ruff, again, when I released it, it was just a side project.

06:11 And it sort of took off, you know, there were, it was originally, you know, I released it in part

06:19 because I had this thesis that like Python tooling could be much faster, and Ruff was meant to evidence that.

06:25 It was meant to be an example of what I saw as like this potential to build

06:29 really different Python tooling.

06:31 And took off a couple big projects, like FastAPI and such were kind of early adopters,

06:39 and it just grew and grew and grew from there.

06:41 And I started a company, Astral, you know, shortly after based on a lot of these ideas.

06:47 So again, Ruff in this context was meant to be, you know, the goal wasn't necessarily to start a company

06:53 just based around Ruff.

06:55 The goal was to start a company based around, you know, the ideas behind Ruff,

06:59 which is can we build really different Python tooling by, well, it's all written in Rust.

07:07 It's sort of an implementation detail, right?

07:09 But ultimately what we're trying to do is build like really high performance Python tooling,

07:13 but also tooling that works together really well and simplifies things.

07:16 So tackle, it's not just about performance.

07:19 It's also about tackling a lot of, I guess what I see as the complexity in Python tooling today

07:24 and really trying to, I guess, challenge certain status quos and respect others,

07:30 but challenge some status quos in what it feels like to work with and use Python.

07:37 And so, you know, our focus as a company, you know, right now we're very, very focused

07:43 on our open source roadmap and our open source tooling.

07:47 So that's Ruff, now UV, which we'll talk about in a bit.

07:52 And these are, you know, MIT licensed, you know, fully open source tools that we build.

07:59 And ultimately our goal is to build and sell paid services that integrate really well with the tooling

08:05 and are kind of like the natural next thing you need when you're building with Python.

08:08 So, you know, we'll never charge money for like the tools themselves, those remain free permissively licensed.

08:14 But our goal is to kind of build, you know, imagine you're building with Python,

08:18 you need to deploy a web server.

08:19 There's a lot of things that you need naturally to do that.

08:22 So for people who are already using our tools, what are the natural next things they need

08:25 and how can we build really good services on top of the tooling that just integrate with it really well?

08:30 So that's kind of the premise of the company.

08:32 There's like really two focuses to the roadmap.

08:35 It's like the open source and the commercial.

08:37 And our goal is to have an incentive structure where we're just continuously aligned

08:41 to like invest a ton in the open source and grow it as much as possible in a really natural way.

08:46 - So you're not gonna do like per line fix pricing.

08:49 You get a million line fixes a month free and then, no, just kidding.

08:52 I think it's an awesome model.

08:55 And, you know, open source 10 years ago, it really looked, it was already super vibrant

09:03 and super making huge dents in the space, right?

09:07 Really a lot of people adopting it.

09:10 But I think there was kind of a funding side that was a little bit missing.

09:14 I still remember like, you know, buy me a coffee type of links, like send me 10 bucks if you like this.

09:21 And that's just, it's not a job.

09:22 That's hardly a hobby type of thing to get stuff done.

09:26 You can't have a team of people focused on it.

09:28 And it had traditionally really been around kind of a beneficial, I need to find a big tech company

09:36 that's willing to give me sufficient amount of time to work on this project to sort of fund its existence.

09:42 Or maybe I'm a consultant and I create Flask, but I consult on Flask, that type of thing, right?

09:48 And I think it's just super positive to see more direct ways people are making open source successful.

09:54 You know, I think-

09:55 - Yeah, I appreciate that.

09:56 And I wish, you know, I sort of wish that there were more good examples of that working.

10:03 There are some for sure.

10:04 You know, for me, it was pretty clear.

10:07 Like it was immediately clear to me I needed to be working on a ruff full time

10:10 if I wanted the project to succeed.

10:11 And that's kind of a microcosm of the bigger challenge, which is like we wanted to build,

10:16 like we really wanted to like professionalize the building of this, you know, the work on this project

10:22 and bring in more people to help build it.

10:24 And so, you know, ultimately it's not, obviously it's not charity.

10:28 It is venture funding.

10:29 And ultimately we need to build a business, you know, around the tooling to make it,

10:35 you know, to make it sustainable.

10:37 But, you know, again, for me, I want the incentive structure to be such that like

10:42 the open source is obviously free, open source, extremely permissively licensed,

10:47 and truly open source.

10:50 Like we have tons and tons of contributors.

10:52 We have a huge community around it.

10:54 And I'm just glad that we've been able to bring in more people to kind of supercharge

11:01 the development of it all.

11:02 So yeah, so I guess you talked on this before, but we're now eight people.

11:08 So we've grown, you know, it was, I guess a year ago it was just me in March.

11:14 So over the past, yeah, our first two team members joined actually in March

11:20 of last year, so almost exactly a year.

11:22 And yeah, we're completely distributed.

11:24 So we're, you know, we have people in US Pacific time all the way to Bangalore.

11:31 So we're just, you know, around the like open source, like we're kind of all over the world

11:37 and just building, you know, building all this stuff out in the open.

11:41 - It's such a good fit to be a distributed company as an open source with open source roots,

11:47 because the tools of open source, in some degree for software in general,

11:51 but especially for open source is asynchronous, semi-connected, you know, kind of the Zen of get,

11:58 but for the way you work, right.

12:00 And it makes it super easy to hire just the most engaged people, regardless of where they are.

12:04 - Yeah, exactly.

12:05 - Rather than the people who are willing to commute to my office in the office park.

12:08 - Yeah, it was, I would be pretty surprised if a single person I've hired

12:14 would have been willing to move to New York, which is where I'm based.

12:19 So from that perspective, it was a no brainer, which is, and actually, you know, multiple people we've hired,

12:26 our relationship with them started on the repo.

12:29 - Yeah.

12:30 - In rough itself.

12:32 And then almost everyone we've hired, we discovered through open source in some way

12:38 or had some relationship through open source in some way.

12:40 - Yeah.

12:41 - So yeah, it's been a really, it's very much in, it's also very much in the DNA of the company,

12:46 which is, you know, we actually also intentionally try to hire people who have been maintainers, right?

12:51 And have a lot of experience with that too.

12:53 We view that as a really important skill.

12:55 - Yeah, that's excellent.

12:56 So we talked about rough.

12:59 One thing I do wanna give a bit of a shout out to is, I don't remember, I think I found this on Mastodon,

13:05 I can't remember where somebody talked about it, but one of the things that ruff does,

13:10 one, it changes code, which is awesome.

13:12 I love your ruff format story, but it also just tells you, hey, this could be better.

13:16 You're violating PEP 8, you're violating this other convention or even a security thing, right?

13:22 But the why of that, I think requires a little bit of experience.

13:26 Like, why should I use this kind of loop or that kind of comprehension over another, right?

13:34 People told me that who are much better have been doing this longer, I shouldn't do it.

13:38 Why?

13:39 When you have 700 rules, there's a lot of why.

13:42 And so you guys came up with this thing at docs.astral.sh/ruff/rules, put in links that literally for each one of these

13:51 has like a little example and what is good and what is bad and when you should use it and so on.

13:57 You wanna just tell people about this a bit?

13:59 I think it's a massive--

14:00 - Yeah, totally.

14:01 So we didn't have, I mean, we obviously didn't have this when we started the project

14:04 and then we accumulated a lot of rules.

14:08 When we decided to add this, I think we already had like hundreds of rules

14:12 and the motivation for the format really comes from Clippy, which is the linter used in Rust.

14:20 - Okay.

14:21 - And they have really, Rust in general has a really good documentation culture

14:25 and Clippy has this nice format, very similar to ours.

14:27 We've made some adjustments, but it's pretty similar around how you document lint rules,

14:32 like what's the motivation and giving examples.

14:35 And so we were like, all right, let's, we wanna do this.

14:37 And we just over a very long period of time and a lot of contributors contributed on this documentation,

14:43 but it took like six months or something probably to document it all. - I can imagine.

14:46 - And now, yeah, now we can, now we require it for all rules.

14:49 So it's much easier to add going forward, but it was a huge effort to add this.

14:54 And some of the explanations too are very extensive and detailed with lots of references.

15:01 - Yeah.

15:02 Yeah, I pulled the one up for isort, unsorted imports, which is error I001.

15:08 And it also talks about whether it can automatically fix it, what this does, why is it bad?

15:13 So it says things like consistency is good.

15:15 Use a common convention for imports to make your code more readable and idiomatic or Pydantic.

15:20 And it just gives an example, bad, good.

15:23 - Right, right.

15:24 - I think that's nice.

15:25 - Yeah, and we've started to put more stuff in here over time too, like whether, like in some cases,

15:30 we let users apply automatic fixes that aren't completely safe, like by opting in,

15:36 like it might change the meaning of your code and you kind of need to be careful.

15:39 And so over time, we've started to document that here too, like rules that have unsafe fixes, why?

15:44 Like in what case might it break your code and what should you look out for?

15:48 So yeah, we want it to be a tool with really good, like we're kind of inspired by Rust in this way

15:56 'cause Rust has a really good documentation culture and also the Rust like compiler itself

16:00 has really good error messages.

16:02 It's sort of famous for that.

16:03 Like when your code doesn't work, it's really good at telling you why.

16:06 Doesn't always get it right, but it has famously good error messages.

16:09 And that's something that we try and channel too, to like when we make changes to configuration,

16:14 like just putting extra effort into trying to make like those like error messages and those hints helpful.

16:19 But yeah, it's a lot of work.

16:20 So I appreciate that you called it out.

16:22 - I'm sure it looks like a lot of work, but it's one of those things that's,

16:28 where else are you gonna get this knowledge, right?

16:29 I mean, I know you can go search for one at a time, but in this aggregate, this is really good.

16:34 - Right, right, right.

16:36 This portion of Talk Python to Me is brought to you by Neo4j.

16:40 Do you know Neo4j?

16:42 Neo4j is a native graph database.

16:45 And if the slowest part of your data access patterns involves computing relationships,

16:50 why not use a database that stores those relationships directly in the database,

16:55 unlike your typical relational one.

16:57 A graph database lets you model the data the way it looks in the real world,

17:00 instead of forcing it into rows and columns.

17:04 It's time to stop asking a relational database to do more than they were made for

17:08 and simplify complex data models with graphs.

17:12 If you haven't used a graph database before, you might be wondering about common use cases.

17:16 You know, what's it for?

17:18 Here are just a few.

17:19 Detecting fraud, enhancing AI, managing supply chains, gaining a 360 degree view of your data

17:26 and anywhere else you have highly connected data.

17:30 To use Neo4j from Python, it's a simple pip install Neo4j.

17:35 And to help you get started, their docs include a sample web app demonstrating how to use it both from Flask and FastAPI.

17:43 Find it in their docs or search GitHub for Neo4j movies application quick start.

17:47 Developers are solving some of the world's biggest problems with graphs.

17:51 Now it's your turn.

17:52 Visit talkpython.fm/neo4j to get started.

17:57 That's talkpython.fm/neo4j, the number four and the letter J.

18:02 Thank you to Neo4j for supporting Talk Python to Me.

18:05 So Ruff will fix a lot of these things for you.

18:09 And one of the things that I like to do is I just have it integrated into my editor these days.

18:15 So both with PyCharm and with VS Code, if I just say format this document, that's Ruff format.

18:21 - Nice.

18:22 Yeah, yeah.

18:23 So we have a VS Code extension and it supports formatting, auto fixing, all that kind of stuff.

18:31 - The PyCharm one's a, JetBrains one's a third party one, right?

18:35 Someone else decided to make that?

18:36 - Yeah, the JetBrains one is by Udai.

18:40 And it's, yeah, that's like a community extension.

18:45 We're considering doing our own at some point because there's a lot of demand for,

18:50 obviously we have a lot of users who use the JetBrains stuff.

18:53 I mean, I use it.

18:55 So we may do it and do our own at some point, but there's a community maintained one right now.

18:58 And that's based on, we have a sort of like a language server.

19:02 So there's kind of like an underlying piece of technology that wraps Ruff that powers all of these editor integrations.

19:08 So like, you can also use that from like NeoVim or like Sublime Text or Emacs,

19:13 like all of those editors support the LSP.

19:16 And so you can actually, it's the same thing that powers the VS Code extension,

19:20 just that's wrapped in some VS Code specific stuff, but like it's the same piece of technology.

19:26 And we're actually rewriting that right now to make it sort of like more natively integrated into Ruff,

19:33 which will let us do some cool things.

19:34 So it should get like actually significantly better, I think over the course of this year,

19:39 'cause it's becoming more and more of a priority for us.

19:42 - Yeah, cool.

19:43 The whole LSP thing is pretty interesting.

19:45 I think it's really opened up a lot of editors being better.

19:48 - Yeah, it has.

19:49 And it made it like from our perspective, it made it way easier to build like editor integrations

19:55 because we just built an LSP and then it like works for like everyone almost.

20:01 - Yeah.

20:04 - Like the JetBrains stuff, it does support the LSP, but I think only in the paid version,

20:10 not in the community version.

20:11 So like there's some limitations around it, but in general, like if you support the LSP,

20:15 like it's actually very easy to build editor integrations that work with everyone, which is like super, super useful.

20:21 - Yeah, sort of rebuilding your own integration for every single thing, which is not fun.

20:26 - Yeah, it's a lot.

20:27 - All right.

20:28 Well, let's talk about the main project here.

20:32 The main reason for being here today is UV.

20:36 Tell people what UV is.

20:37 This is your next big project, next big tool.

20:40 - Yes, yeah.

20:41 UV, we released UV a little under a month ago.

20:46 And this is something that I've wanted to do, like basically since we started the company,

20:53 I wanted to start, I thought there was an opportunity to build some really interesting tooling

20:58 in Python packaging.

21:00 And UV is kind of the first milestone in that.

21:03 So UV in its current form, it's designed as a sort of drop-in alternative

21:12 to pip, pip tools, like if you use pip compile, pip sync and virtualenv.

21:17 So it takes those three tools and tries to bundle them into one.

21:22 And so it can do things like, given a set of input requirements, generate a requirements.txt file,

21:30 similar to what you'd get from pip compile.

21:33 It can, you can do UV pip install -r requirements.txt, UV pip install black.

21:40 So it's really intended right now to be a sort of, it won't always, we don't support absolutely 100% of what pip does,

21:51 but it's, we try to be pretty close.

21:53 And so in many cases, the intention is that people can basically drop in UV

21:59 in their project that uses pip today and get in many cases, like very, very significant performance improvements.

22:08 So similar to ruff, like some of the goals we had for this project were one,

22:12 it should be very, very fast.

22:15 And UV, it's really fast.

22:18 In particular, there's like a benchmarks.md in here, actually, if you want to click on that.

22:26 Now scroll up.

22:27 - Does that do it?

22:28 - Oh yeah, that works too, I guess.

22:30 That was smart of me.

22:31 Yeah, so it's really, really fast, especially if you've already have, if you're, if you have things cached,

22:41 which is pretty common.

22:41 So like often on your machine, when you're doing like pip install -r, whatever,

22:47 a lot of those packages, you've probably installed them at least like once before

22:50 on your machine, or maybe you deleted your virtual environment and you're recreating it with the exact same dependencies

22:57 or something like that.

22:58 UV is like very, very well optimized for that case.

23:02 So if you have a package that you're installing multiple times, like the installation is effectively free.

23:09 And it's also a lot more like disk space efficient.

23:12 We use kind of like, we store all of them in one place and kind of copy them into your virtual environment

23:17 so that you don't have like many, many different copies of the package too.

23:20 So this was all kind of taking techniques and inspiration from like other ecosystems

23:27 and other package managers and kind of molding them to fit Python's model

23:32 for how packaging and dependencies work and all the specifications.

23:37 And so again, the end result is like you, installing into a virtual environment,

23:42 a package that you've already installed before is basically free.

23:45 And yeah, a lot of these things are just like way, way, way faster.

23:49 Similar to ruff like-

23:51 - Dramatically faster, yeah.

23:53 - Yeah, and similar to rough like-

23:54 - Dramatically, and I think, you know, it's worth pointing out that like on one hand,

23:59 we all have an extra 10 seconds, right?

24:01 Or whatever. - Of course.

24:04 - But in the aggregate, all of these things are just like little paper cuts

24:08 over your day, you know?

24:09 And so, yeah, sure, I can format the code and I could use something nice

24:13 and sure if it takes 20 seconds, okay.

24:16 But then you stop running it 'cause it's kind of a hassle and you're just,

24:18 you're in your flow.

24:20 And this is kind of the same way.

24:22 It's like, oh, I wanted maybe see if there's a new, some new packages for this project

24:26 as I'm sitting down to work on it.

24:28 Like, okay, well, wait for a pip compile to run and you wait and you wait and then like,

24:33 okay, now it's done onto the development version and you wait and you wait.

24:37 And like, you know, it's just some of these things that are instant.

24:41 - Just ask the question more and it just doesn't break your train of thought, you know?

24:45 - Totally.

24:46 I think there's like, maybe like three different things that come to mind here when we think about performance.

24:51 'Cause like, yeah, okay, in this case, like it may not seem to change your life

24:55 if you're going from one second to, you know, 50 milliseconds.

24:59 But I think three things come to mind.

25:00 So one, like for companies and large projects, this can actually be like a really big difference.

25:06 And so if you're at a company and you have like a big monorepo with like a bunch of different sub projects

25:13 and they all have requirements files and you wanna bump a dependency, that can be like, at that point you're talking

25:18 like 15 plus minutes for a command.

25:22 And so like, the larger the project gets, obviously the more performance matters

25:26 and the more it helps out.

25:28 And we're trying to build tooling that can basically scale, I don't know about like to arbitrarily large projects,

25:32 but like to large projects and useful for companies too.

25:35 You know, the other thing I'd say is I think there's something that happens like when tools,

25:42 when you make something like way faster, it just changes a lot of the ergonomics

25:46 around what it's like to do things.

25:48 And so, you know, in this case, like, okay, so installing into a virtual environment,

25:54 a package that you've already installed before is free now.

25:57 And so how does that change things?

25:59 It's nearly instant.

26:00 So how does that change things, right?

26:01 So that means like, if you mess up your virtual environment and have to delete it and recreate it,

26:06 it doesn't cost you anything.

26:07 It's totally ephemeral.

26:09 You can throw it away and recreate it at any time.

26:11 And like, that's just like a different, like it sounds small, but that's kind of like a different relationship

26:15 to a virtual environments than before, where it's like, okay, I created the virtual environment now.

26:18 Oh no, my virtual environments have messed up.

26:20 I got to recreate it.

26:21 Like we want to just change a lot of the dynamics around some of those like abstractions.

26:25 And then the other thing is this performance budget or this, if you think of performance like a budget,

26:30 this buys us a lot of room.

26:32 And so like the fact that we are so fast on some of these things means that we can do things

26:39 that otherwise might be like prohibitively slow.

26:41 And this is more sort of forward-looking and for the future.

26:44 Like one thing that we're thinking about a lot right now is this idea of like resolving Python dependencies

26:49 for many platforms, because it's a little bit complicated, but you know, pip compile and pip and UV,

26:56 they're really designed to only work on like the current Python platform

27:00 and the current Python that you're using.

27:02 So if you're on like macOS and you run pip compile, or UV pip compile, it will give you dependencies

27:08 that are correct for like macOS and your current Python version, but they might be wrong on Windows because Python,

27:16 in Python you can have dependencies that vary based on things like the current Python version

27:20 or the current operating system.

27:22 - Yeah, so one example would be a UV loop, right?

27:26 For people who are trying to speed up.

27:27 - I think it doesn't work on Windows.

27:29 - It doesn't work at all on Windows, that's right.

27:31 And so.

27:31 - Yeah, so that's a very common one.

27:33 - Yeah.

27:34 And it is, I think very common that this hap, that, you know, this is a very common thing,

27:38 like on like lots of really, really popular packages have these kinds of marker.

27:43 These were called markers, which basically makes the dependencies conditional

27:47 based on the current Python.

27:49 And so, you know, like again, like in pip and pip tools, UV right now just locks for the current Python.

27:57 Poetry and I think PDM, but poetry for sure does this very interesting thing

28:03 where they actually try to lock, they try to resolve for like all possible platforms.

28:08 And that's something, it's really convenient because it means that like you kind of do one lock

28:14 and then any user anywhere can like use that and it works.

28:18 And it's kind of like guaranteed to be right as opposed to maybe it doesn't work on Windows

28:24 or whatever else.

28:24 And so we're pretty interested in like that, adding that behavior and that's gonna be like more expensive.

28:30 And so if we have something that's really fast right now, it kind of like opens up a design space

28:35 of interesting things we can do to solve that problem while still being, you know, very fast.

28:41 So that's kind of how I think about performance.

28:44 Like I think people like a little bit underrate how much of an impact it can have

28:49 on even small interactions.

28:51 'Cause once you try something that's much faster, it's often hard to go back to the other thing.

28:55 But I'm glad you've had that experience at least.

28:59 - Yeah, absolutely.

29:00 A couple of interesting comments.

29:02 Dane says, "If it takes 10 seconds, "I go to triage that issue on GitHub

29:06 "and come back five minutes later." Right, like that's kind of where I was getting at

29:09 with the flow stuff.

29:10 It's like, okay, I'm ready to go.

29:12 Mind wonders and you're kind of like starting over.

29:15 - Yeah, yeah, yeah.

29:16 - And then Henry out in the audience also says, "Hey Henry," it says, "It also, this doing things so quickly,

29:23 "it encourages good environment usage "because if doing things the right way

29:26 "is just as easy and as fast as doing it the wrong way, "you might as well do it the right way."

29:29 - That's a nice thought.

29:30 That's a nice thought.

29:31 - Yeah, it is.

29:32 - Yeah, I mean, I think there's, yeah, there are certain things though where like we aren't any faster

29:39 and I'm interested in thinking about like those and what we can do about them.

29:44 Like a common one or the most obvious one is in Python sometimes when you install a dependency,

29:51 you might have to build it from source.

29:54 And in Python, you often are installing things like NumPy, which have include some native code.

30:01 And so actually turning that into something that your system can run is kind of expensive.

30:06 And you typically don't have to think about this with NumPy because they ship what are called wheels,

30:11 which are kind of like these pre-compiled artifacts.

30:15 But not all packages ship wheels.

30:19 You could be on a platform that doesn't have a wheel for a variety of reasons.

30:22 You might get the raw NumPy source code and then have to, you get the raw NumPy source code

30:30 and then have to compile it down into a build distribution.

30:33 And like for us, if we get into that situation, it's like not gonna be any faster

30:38 because like we still have to build the thing from source.

30:41 Like just like that.

30:42 - That's the slowest part of the whole process.

30:44 - Yeah, and so there's like some, you know, there are some cases and some bottlenecks

30:48 where like it's, I'm kind of thinking about how could we do even better there?

30:52 And there are actually things that are changing in the standards that have made this a little easier.

30:55 Like there's this new thing called metadata 2.2.

30:58 It sounds cool, I know.

30:59 It basically lets you like read the metadata.

31:03 - You like metadata 2.1.

31:05 - Yeah, if you, yeah, I'm on, yeah, we're actually on 2.3 now.

31:09 - I just get it.

31:12 - But the point of that is like, it's a standard that makes it so you don't have to build the thing as often.

31:19 Like if you just wanna know the metadata of NumPy, for example, you may no longer need to build it

31:24 and before you did.

31:25 And so the standards are moving in a helpful direction here, but I just thought I'd call it out

31:29 because like the source distribution, there are cases where it won't be faster

31:33 and I'm pretty interested in those, but people should know that they also exist.

31:38 - There's also, it's not just time, there's also security issues around that, right?

31:43 If things are still based on building source from source and then running the setup py to see what the metadata is,

31:51 it's both slow and also potentially running arbitrary code just to install a thing, which can make you,

31:56 I mean, I don't know, rarely has anything gone wrong with just installing and running arbitrary code

32:01 off the internet, but sometimes it could go wrong.

32:03 - Yeah, it would be nice to get to a world where that's not required or at least for dependency resolution

32:11 and like the standards are moving in that direction.

32:14 - Yeah, exactly.

32:14 I mean, you might, if you're gonna use it, you're gonna have to get it, but if you just wanna know,

32:17 well, what versions do I need to put these two things together?

32:20 You shouldn't have to do that.

32:21 - Yeah, exactly.

32:22 Because today for NumPy, for example, if you didn't have a wheel, you would have to run some arbitrary code

32:27 to ask it for its dependencies.

32:29 - Yeah, exactly.

32:30 Well, let's talk about some of the usages here.

32:32 Let's see some more interesting comments in the chat.

32:35 We'll get back to them.

32:36 First of all, is it like Highlander, the movie, should there just be one?

32:42 Is this, is UPI a thing that I put into, say my requirements file if I wanna use it

32:47 or do I install it just once for my machine?

32:50 Like what's the scale?

32:51 - Yeah, so there's a lot of different ways.

32:54 You can, there's a lot of different ways to install it.

32:56 You definitely can install it into a virtual environment.

32:59 My general recommendation would be to install it on your machine once, because an interesting thing about UV

33:06 is you don't need Python to install it.

33:10 And it doesn't have, you need to have Python on your machine because we need to be able to, for example,

33:16 build source distributions or know where to install the thing, right?

33:19 We have to install into a virtual environment somewhere.

33:22 And so you have to have Python installed on your machine, but UV does not depend on Python.

33:28 So like it can install into arbitrary virtual environments or into arbitrary other Python interpreters.

33:34 So that's why we generally recommend using like the, these standalone installers that we have at the top

33:40 of the snippet on the screen.

33:42 They're like the curl and the PowerShell invocations.

33:45 Those will install a binary, a single binary on your machine that's UV.

33:51 And from there you can use UV to install into virtual environments that it creates,

33:57 to install into your system Python, to do whatever.

34:01 So like I would say most people, based on the statistics, based on our download statistics,

34:06 most people still install UV with pip, which makes sense, which is not that surprising to me.

34:11 But I would generally recommend having like one UV install on your machine.

34:16 Although if you do install into a virtual environment, like that's also totally fine.

34:19 Like nothing's gonna go wrong.

34:21 It's just not completely necessary because a single UV can already install

34:25 into that virtual environment.

34:26 - Right.

34:27 You're never going to import UV.

34:29 - No. - I mean, you might, but in general, people are not going to.

34:33 - I think you can.

34:34 I'm trying to think what would happen.

34:36 (laughs)

34:38 - It's not like, like things like pytest and other things.

34:42 A lot of times there could be just one of those, but then you wanna use fixtures

34:47 and you need to import something out.

34:49 So then it really needs to be in the virtual environment and accessible like a library.

34:52 But this is just something you run maybe even before your codes, before your virtual environment exists, right?

34:57 Like it really kind of does ideally exist outside it, I think.

35:02 - Yeah, ideally it exists outside of it.

35:03 And there are some cases where you'd wanna install it within the virtual environment,

35:06 but ideally it exists outside of it.

35:07 The other thing that's nice about using the standalone installers, like at the top here is,

35:13 soon we're gonna ship like a self update command.

35:16 So you can do like UV self update and it will update UV to the latest version.

35:20 And we can't really support that if you install it with a different package manager

35:24 like pip or Brew.

35:25 Those have their own upgrade commands obviously, but like if you install it with our installer,

35:30 then like we can control the upgrades and stuff like that and provide some other features.

35:36 So that's generally what we recommend, but obviously we're always gonna support

35:39 like installing with pip and stuff too.

35:41 - Yeah, I'm all about PipX these days.

35:44 I really like--

35:45 - Yeah, we're PipX, that's mine.

35:47 - Yeah, yeah, PipX really, you can just say up, kind of like Brew, you can say upgrade all my Python CLI tools,

35:54 PipX upgrade all.

35:56 Basically I find ruff and UV is just, you guys are moving super fast and there's frequently an update.

36:03 - There are often updates, yeah.

36:05 Yeah, and then the UV interface, like it's meant to be pretty familiar to,

36:11 or it's meant to be, I guess, hopefully very familiar to people who have used,

36:16 who are already using pip and other tools.

36:18 And so like UVVM creates a virtual environment.

36:22 And then there's, we have this sort of pip sub command.

36:27 So like UVPip install Flask, and that doesn't call or use pip in any way.

36:33 We're just using pip here to convey what the interface looks like.

36:38 And part of the motivation there is at some point in the future, we probably wanna add a new interface to UV

36:46 that's a little bit more high level.

36:50 So you could think of something like Poetry, where they have like Poetry install,

36:55 they have this sort of higher level interface for interfacing with packages.

37:00 We wanna do something like that.

37:02 And so that's why we left the top level of the interface clear, because we might kind of like integrate and,

37:10 sorry, innovate and like ship a bunch of stuff that would otherwise break this interface.

37:14 So like by putting this stuff under Pip, we basically created this like isolated space

37:19 where we can make sure that those commands like keep working no matter what we choose to change

37:23 in the future.

37:24 And it's very similar to Pip's interface, right?

37:27 It's like pip install, then it could be a package name.

37:29 It could be a dash R requirements file.

37:32 We support editable installs.

37:34 We support like URL dependencies, get dependencies, all that kind of stuff.

37:39 - Right, all the stuff you might normally do, pip install something for the most part, that's the same.

37:44 - Yep, yeah, exactly.

37:45 And we support a lot of the same flags too that like pip supports.

37:48 So like --index URL, -- extra index URL, like --no binary, like all that stuff.

37:54 Like we've put a lot of, we don't support every flag, but we've put a lot of effort into supporting a lot of them.

38:00 And we've added more over time.

38:01 Like now we support like --no build isolation and stuff like that,

38:05 that maybe most listeners have never even had to look at, but like, yeah, these things matter

38:10 in some circumstances.

38:12 And so like over time, our goal is to add like more of the interface.

38:15 But, you know, I would say for common use cases, I would expect that it just works.

38:22 Like just adding UV up front, like it should just work.

38:26 Now as you become more complex, it won't and you'll run into some.

38:30 We have a whole document of like subtle ways that we deviate some are intentional,

38:35 some I consider bugs, right?

38:36 Like some we want to fix over time.

38:38 But the intention is that for most people, we want it to just work.

38:41 - Once we fix the first round of bugs following the release, of course.

38:44 - Yeah, yeah, sure.

38:46 So you've got a UV, VENV, VIMP for creating a virtual environment.

38:51 And it has a lot of the flags that Python dash MVNV would have where you can say, you know,

38:57 bring along pip or upgrade things or set the prompt name, that kind of stuff, right?

39:02 - Yeah, yeah, exactly.

39:03 Yep.

39:04 - Similar for UV pip and then stuff.

39:06 What I find I do for most of my work, at least if I'm not trying to teach or do a presentation

39:12 where people are like, what did you just do?

39:14 These all have kind of aliases, right?

39:15 Like UV pip install -r requirements on TXT is just PIR, pip install requirements, you know, things like that.

39:22 - Yeah, yeah, yeah.

39:23 - And so try to just take the common stuff and it doesn't matter if it's pip or UV really backing it

39:30 from my CLI ergonomics, right?

39:33 I'm just, I use my alias.

39:35 And if I want to change that, I just go and edit it.

39:38 And so for me, it was super easy to switch to adopt these things because I'm like,

39:43 I added my ZSH RC file once and now everything just, I just do the same stuff and it works,

39:49 but the new way, way faster.

39:51 - Yeah, and you know, the goal of like pip compatibility has been interesting because there are actually like

39:57 some things that we very intentionally want to do differently and like, I won't speak for the pip maintainers

40:03 like, but I think in some cases, there are probably things that they would do differently too

40:07 if they could.

40:08 - I think so too, yeah.

40:09 - Yeah, 'cause like PIP, I mean, PIP's number one, pip is extremely important and its number one goal is like,

40:16 it needs to be like robust, right?

40:19 It needs to keep working and it needs to be compatible and 'cause it's like, it's truly like the cornerstone

40:25 of like a lot of the Python ecosystem.

40:28 And so PIP, it's very, it's harder for them to change things especially in a breaking way.

40:32 And they have to be really thoughtful and do that over a long period of time.

40:36 And so we're in kind of a privileged position, honestly, because we come in with a new tool,

40:41 we can actually do a bunch of, choose to do things differently.

40:44 And some people get upset about it obviously, 'cause they're like, this isn't exactly how pip does it.

40:49 I'm trying to hold firm on some of those things and also be open-minded on others, right?

40:53 But like, you know, like one thing that we do that's different, that's, I guess maybe it's not evident

40:59 from this screen exactly, or I guess it sort of is.

41:01 So when you do UVVM, we default the name .vm.

41:05 So like, if you don't provide a name, we just default to .vm.

41:09 And there was a PEP to make that a standard that got pulled back, but like,

41:14 it's not like we're trying to make it a standard, but I just think it's a good default.

41:17 Like we want to abstract away some of this stuff.

41:18 And so you can just like have a virtual, you can obviously pass a name if you want,

41:22 but we default to .vm.

41:23 That's different from other tools.

41:24 And then, you know, the other thing is when you do UVPIP install, by default we require a virtual environment.

41:31 And so if you do UVPIP install Flask and there's no virtual environment,

41:36 like we'll throw, we'll error.

41:38 And it doesn't have to be active.

41:40 We'll look for it in the current directory, even if it's not active.

41:42 So like, if you do UVVM, then UVPIP install Flask, like it will work.

41:46 And in my opinion, it will do the intuitive thing, which is it will install it into the environment

41:50 in the current directory.

41:51 So it's like, it's trying to provide-

41:52 - It'll traverse up?

41:53 Like if I'm a little farther down, it'll go up and say, "Oh, just, oh, that's amazing."

41:58 - Exactly.

41:59 So it'll find the virtual environment in the current directory or any parent directory.

42:02 So like, for me, that's just like a nice default workflow that encourages virtual environments

42:10 and like doesn't get in your way about it.

42:11 And we do have a flag for installing outside virtual environments, but the difference is in UV, you have to opt in

42:17 if you want to do something like install into the system Python.

42:21 The virtual environment, it's a very virtual environment first while abstracting away a lot of the details

42:25 of virtual environments.

42:27 So, you know, there are things like that where we made intentional decisions.

42:30 - Yeah. - In my opinion, yeah.

42:32 - Yeah.

42:33 - Yeah.

42:34 And I think, and it's nice because we can start with that behavior and, you know, we're in a privileged position

42:40 'cause we can start with different defaults.

42:42 - Yeah, for sure.

42:43 So if I do, excuse me, if I do a UV, VNV for a virtual environment, then maybe I UV pip install something,

42:54 but then I forget and I pip install something else.

42:58 Does it break?

42:59 Is it okay?

43:00 - As in the third time there's no UV?

43:02 - Well, yeah, exactly.

43:03 Like, so I'm in UV pip install something, UV pip install that.

43:07 And I was, oh, I forgot this thing.

43:08 I was pip install.

43:09 Oh, I forgot the UV.

43:11 To the state-- - No, it shouldn't break.

43:13 Assuming, so let's say you activate the virtual environment.

43:16 - Yeah, yeah, it's already activated.

43:17 - Okay, cool.

43:18 So you do UV VM, you activate the virtual environment, you do UV pip install flask,

43:22 and then you do pip install black or whatever.

43:24 - Yeah, something, yeah.

43:25 - That should work just fine because like the thing that we ultimately create

43:30 in the virtual environment, like that's all based on standards.

43:33 So like the stuff that we do in the virtual environment to install packages,

43:37 it should look like roughly indistinguishable from what pip would do.

43:41 And it's totally interoperable with pip.

43:43 So like similarly, if you did pip install and then like pip install flask

43:47 and then UV pip uninstall flask, like that would work correctly.

43:51 Like pip would install flask and we would remove it because everything that pip and UV are doing

43:55 in the virtual environment is based on standards.

43:58 So the way that we add and remove packages, all that kind of stuff, it should be totally interoperable with other tools.

44:04 - Okay, cool.

44:05 PyPI is pretty good at having analytics around what packages are being downloaded,

44:10 what's popular, what platforms.

44:13 Do you do anything like send a user agent or something so that people could answer the question

44:18 or how many people are using straight pip and how many people are using UV in a year?

44:23 - Yeah, we sent a UV user agent and it's right now it's just UV in the UV version.

44:29 There's an open issue in the repo from Pradyan who works on pip that outlines all this stuff

44:37 that pip includes in its own user agent, which we wanna add, which is pretty interesting.

44:43 I actually didn't know this.

44:44 So pip and its user agent includes a lot of things about the current Python platform,

44:50 data that they use in PyPI basically to inform decisions.

44:57 Oh, no one's using Py...

44:58 This is just, I don't think this is actually how it's used, but just an example.

45:01 Oh, no one's using Python 3.7 anymore.

45:03 Let's lower priority on that because no one's installing Python with Python 3.7.

45:08 And so we wanna add, we don't have that right now.

45:11 We're planning to add it.

45:12 But yeah, it will be interesting to see.

45:16 We can get statistics over time too on UV and pip and how common they are in different dimensions.

45:22 - Yeah.

45:22 One thing that would be kind of fun to have is, I'm not sure if it's at all interesting to you,

45:28 but to have some kind of cron job or background thing, if you just interact with UV,

45:34 if it kind of kicked off sort of a background process that did its thing.

45:37 But take the history of maybe the top 500 packages plus the ones you've used

45:43 and just kind of keep a cache up to date on your system.

45:46 So you're on an airplane or you're in a coffee shop or for some reason, the internet's not great.

45:51 Like it's kind of pre-filled the cache and everything's there.

45:55 And I kind of, that might be fun.

45:59 - Yeah, we do have a dash dash offline flag, which will like, it forbids network requests obviously,

46:05 but it, so like it'll try and do the full install without accessing the network.

46:10 - Yeah, that's cool.

46:10 - It would be cool to pre-fill the cache.

46:12 - Yeah, but it's just like, you know, if you're a UV user and you sit down on your computer

46:16 and for some reason the internet's out, I'm at a conference, I'm doing a talk

46:19 and it's got the dreaded terrible conference wifi.

46:21 It's not the end of your demo.

46:22 It's just like, yeah, see how fast this is.

46:24 It's amazing.

46:25 - Yeah, yeah.

46:26 Yeah, it was actually, it's actually funny 'cause like the benchmarking, like when we do benchmarks,

46:31 like benchmarks can just vary so dramatically based on like internet connectivity, right?

46:36 Like that's often, that is often the bottleneck.

46:38 I mean, it's not, it's clearly not always the bottleneck because we're able to be faster than other tools.

46:44 So like if it was always the bottleneck, I don't think that wouldn't really be true,

46:47 but it matters a lot.

46:49 And so sometimes I'll throw on, on macOS, they have a tool called network link conditioner.

46:54 So you can actually force-

46:56 - Drag your network out.

46:58 - Yeah, you can force it down.

46:59 And the categories are like, it's not literally called like bad mobile phone

47:04 or something, but it's, that's like basically what it is.

47:06 Yeah, it's like, it's like, it's like very lossy edge network.

47:09 Like those are like the pre-built category.

47:11 It's pretty funny, but like it is actually, that's a very helpful thing for benchmarking.

47:15 - Yeah.

47:15 - And sometimes actually, if you have a really good network connection, sometimes it's actually helpful to set that anyway

47:20 to a pretty good level, because then at least it will be like very consistent

47:25 across your executions.

47:27 Anyway, it's something I've learned over time.

47:29 - Yeah, that is super interesting.

47:31 So one of the things I think is interesting to consider here is obviously this is way faster.

47:37 I saw some of the announcements and some of the discussion around the announcements

47:42 and the people were really surprised how fast this is.

47:45 And I think, I don't think Rust is the full answer.

47:48 You mean, you tell me if I'm wrong, but like one part, obviously making the code run ultra fast,

47:53 that is an important part of it.

47:55 But it also seems like you all have rethought some of the internal algorithms and some of the caching

48:01 and some of the ways things work, maybe with a fresh take on it, or you're not constrained by the way it's been done

48:06 for many, many years.

48:07 So what elements are at play to make it as fast as it is?

48:12 Is it just Rust or is it something else?

48:14 - So Rust is important, but like the way I typically talk about, like frame it is that Rust is kind of like an enabler

48:21 to writing really fast programs.

48:23 Like it lets you, it forces you slash lets you care, it forces you to slash lets you care about certain things

48:31 that matter a lot for performance that like in Python, you just act, there's actually just no way

48:35 to care about them.

48:37 Like I'm talking specifically here about like memory allocation, like in Python that all just kind of happens.

48:42 In Rust, you're forced to think about, am I gonna allocate memory here or not?

48:45 And like, when is it gonna be deallocated and all that kind of stuff.

48:49 And so that unlocks the ability to care and like be really careful in how you manage it.

48:54 And so Rust is like a really important, Rust is an important part of the success story here,

48:59 but I think it's like really, I think it would be really like very incorrect to say

49:04 that it's like all about Rust and it's not a Rust versus Python thing.

49:08 Like-- - Right.

49:09 Like if we could just recompile pip with--

49:11 (laughing)

49:13 - Yeah, so if you took--

49:14 - With a Cython or something and boom, it would just be, no, it wouldn't be as big of a deal, right?

49:19 - If you took pip and just like rewrote it line by line as close as you could in Rust,

49:23 like it would probably be faster than Pip, but it would not be nearly as fast as UV.

49:28 Like we just do a lot of things differently.

49:31 And part of like, I guess evidence for this too, is like throughout the development of UV,

49:36 there were like multiple pull requests that sped up like UV as a whole by like 30 to 50%.

49:41 So what does that say?

49:42 That says that like there's lots of different, those were all Rust programs, right?

49:46 So like we were able to write the same Rust program many times, optimizing it more and more and more.

49:52 - Right.

49:53 - And so there's like so much engineering that went into making it fast.

49:57 Some of it's like how the cache is designed.

49:59 That was like a really important piece.

50:01 And that's actually something that like pip could also do.

50:04 And I think like it's possible a good outcome here actually is that like pip is able to take some of these changes

50:11 and incorporate them over time.

50:13 And we are kind of the Guinea pig for that.

50:17 Like we're gonna kind of change user expectations a little bit about how the cache is set up.

50:21 Like we're gonna run into bugs about platform compatibility.

50:26 Like we're gonna run into bugs based on this cache design, right?

50:29 And like hopefully that could at some point help inform pip if they choose to redesign their cache this way.

50:34 The cache design is really big thing.

50:35 And then just a lot of like profiling the program, figuring out what the bottleneck is,

50:42 and then like solving the bottleneck and just like really intense engineering work

50:46 that was not me, but it was like other people on the team to optimize some of that.

50:49 Like a good example is, it's okay, it sounds silly, but like we found that a bottleneck

50:55 when all the data is cached and you're trying to do a resolution.

50:57 So there's no network requests, everything's local.

51:00 One of the bottlenecks that we kept running into was parsing and comparing versions, version specifiers.

51:07 So like in Python, when you have a requirements file, you have like FastAPI is greater than version one

51:14 or whatever.

51:15 And then in the FastAPI file, you have like FastAPI version 1.0.0, blah, blah, blah.

51:20 So like those, like parsing those, and then we were comparing those.

51:25 We were doing comparisons between version markers like so many times, because it was just a constant thing

51:32 in dependency resolution.

51:32 It's like, can I use this dependency?

51:34 Well, does it fit to this range?

51:36 - So Andrew Gallant from our team, like rewrote that parser and the version comparison specifier.

51:44 And it's like one of the most incredible pull requests I've ever seen.

51:47 Like it's like so interesting.

51:48 Like every commitment is like so interesting.

51:51 And he like optimized it so massively that it was like, he's basically representing the version in the end

51:56 by like a 64 bit, like a U64 integer.

52:01 And comparisons is just like compare the two integers.

52:03 And like, there was just so much engineering that went into it.

52:06 And it sped up the cache case by like 30%.

52:07 And so there's a lot of, there's just a lot of engineering that went into it.

52:12 And, you know, again, it's harder for pip to do some of those things 'cause the code bases,

52:18 they have a lot, they have actual users to support, right?

52:22 Like we were able to do this before we launched publicly, like we could break things,

52:26 like we can do things, you know, we can make massive changes to the code base

52:30 in short periods of time.

52:31 So, you know, we're in kind of a privileged position to be able to really optimize the performance like that.

52:36 But, you know, it's a big part culturally of what we wanted to do too, is like, we're gonna make this thing extremely fast.

52:42 - Yeah, I'm seeing also interesting secondary effects, you know, talks and not, not,

52:48 I guess talks, talking about using it, making it faster.

52:52 Just now I hear Henry says, "Build 1.1 is faster from looking at UV." And the next version will also add UV as an installer choice,

52:59 which is pretty impressive.

53:01 - Yeah, that's been a really cool, that's actually something I didn't really anticipate,

53:05 but I'm really glad has happened, which is that there's a little bit of like,

53:10 we ended up building something pretty modular.

53:12 And so there's been a little bit of, or a lot of like integrations with UV

53:17 that people have been building.

53:18 Like, like Bernat had the talks UV thing that was out like within a week, I think,

53:25 which was like use UV to power talks in different ways.

53:29 Yeah, Knox, I think supports it, build, pypi/build.

53:33 - Ah.

53:34 - You know, I've talked to the Hatch maintainer, you know, like he's pretty interested in making UV

53:41 like an optional backend for Hatch.

53:43 So like, that's really cool to me 'cause it's all just like magnifying the impact.

53:48 And again, I don't know how much of that I anticipated, but it's really cool to see that like,

53:55 you could plug it into these other tools and they can just like go much faster.

53:59 So I don't know, for me, that's been like, that's actually been like a big highlight

54:03 from the release, honestly, has been the reception from like other maintainers

54:06 of other tools who have been excited to integrate it in different ways.

54:09 'Cause it's just not, it just didn't happen.

54:12 Like ruff wasn't nearly as much of a fit for that kind of thing.

54:16 Like there just aren't as nearly, there are some, but it's just not as natural to have like integrations

54:20 with rough in that way.

54:22 But for UV, it makes a lot of sense and it's been really cool to see.

54:24 - Yeah, it's more, UV is more of a building block than rough is.

54:27 Ruff fits in editors and CI and stuff.

54:30 Yeah, okay.

54:31 - There were other tools, but yeah, it's mostly an end user thing and not a library, I think.

54:38 - Right, all right.

54:39 So a couple of interesting things out in the audience.

54:41 Let's knock them out.

54:42 Okay, so Tushar asks, and this is, I think, a big tension that's building in the Python packaging space

54:50 is do packaging tools use Python to do stuff?

54:54 Or do the packaging tools control the Python?

54:56 Who is controlling whom here?

54:59 And so Tushar asks, will UV also install Python sometime soon?

55:02 Can I just express, hey, I wanna use 3.12 on this in these dependencies?

55:07 - Yeah, we almost certainly wanna do this.

55:10 I don't think it will be, it won't be required.

55:13 Like you can still use your own Python, but we almost certainly want to add Python bootstrapping.

55:19 So like, that's another reason why the dream workflow is like you use the standalone UV installer

55:26 because then it's like, it will actually install Python for you too.

55:30 And so like the reason, so then it's like, you don't have to have Python on your machine basically

55:35 to start being productive with UV.

55:37 You can just bootstrap the environment for you.

55:39 And we can also do, you know, yeah, it would just be nice if you did, you know,

55:44 pip compile, like UV pip compile, --Python 3.13 or something.

55:50 And then we just like bootstrapped Python 3.13 and did the resolution on your machine.

55:54 Like that's kind of the workflow that we're trying to build towards.

55:56 - Yeah, since you're so UV centric as well, it could be UV, VNV, you know, dash dash version.

56:02 - Yeah, a hundred percent.

56:03 - 3.12 or whatever.

56:04 - And then we bootstrap it, yeah.

56:05 - If you don't have, if you've got a cache, you just give it.

56:07 And if you don't, then you get it on the machine.

56:09 - Exactly.

56:10 - Yeah.

56:11 - Yeah, so we'll definitely do this.

56:13 Again, I do think it's important that it's not like required to use like the UV Pythons.

56:17 We actually kind of had to do like a minimal version of this for our CI and testing.

56:25 But it was a batch script and then I think it became a Python script, but eventually it would be like built into UV.

56:32 Yeah.

56:33 - Yeah, yeah.

56:34 I think that would be really.

56:34 - Yeah, I think it'll be super cool.

56:35 - Really quite awesome.

56:36 - Yeah, I think it will be too.

56:38 Let's see.

56:39 Tushar also says, loves that the dash dash require VNV.

56:43 - Yep.

56:44 - As a thing.

56:45 He thinks it'll become the default and also points out for those who don't UV

56:49 that pip require virtual VNV as an environment flag is in your RC files.

56:53 It's pretty nice.

56:54 I need to do that just the other day.

56:55 - Yeah, you can.

56:56 - Oh, I spelled that to the wrong spot.

57:00 - Yeah, so pip can be configured to require virtual ends.

57:03 - Yes.

57:04 - Yeah, I do something weird.

57:05 I'm actually looking at my terminal behind our shared screen, our meeting here.

57:09 And my prompt says global VNV.

57:12 And so one of the things that I do is have a, just if I log it, if I open up my terminal,

57:16 it already has an activated virtual environment.

57:18 It's just for whatever.

57:20 - Oh, interesting.

57:20 To just avoid messing up your system Python.

57:22 - Just to avoid messing it up.

57:23 Or so I can have, I can just make that virtual environment the version of Python I want it to be,

57:28 even if it's not the system one in general that I want to set, you know, just like,

57:32 it's its own thing.

57:33 And so it wouldn't actually help me, but I still like that.

57:35 - That's smart.

57:36 Yeah, that's smart.

57:37 (laughs)

57:38 - Thanks.

57:39 - Yeah, I've learned a lot about like, oh my gosh.

57:42 I mean, I've learned a lot about packaging.

57:43 Like I didn't know like anything about packaging, you know, like six months ago.

57:48 I shouldn't, I should actually shouldn't admit that 'cause it's really bad for my credibility,

57:51 but like I've learned a lot about packaging and in the past like two weeks,

57:56 I've also learned a lot about like system Pythons, like how Python is installed

58:02 and like how on like older versions of like Debian, like Python, they do like a lot of customization to Python

58:09 that makes it like really different from like, and I learned like way more about this

58:13 than I ever thought I would.

58:15 - I think it's fine to say that.

58:16 - I'm out on system Pythons, but we do support them.

58:18 - Yeah, awesome.

58:19 You know, someone asked me like, no, Michael, you must know all of the standard library.

58:24 I'm like, what are you crazy?

58:25 No.

58:26 - Yeah.

58:27 - Why would I want to know everything?

58:28 Yes, exactly.

58:29 And I think it's the same thing about packaging.

58:31 There's like so many edge cases.

58:33 If you never interact with an edge case and you don't care about that edge case,

58:36 why would you take the week or whatever to study it?

58:38 Like it's just, it's irrelevant to you until you need it.

58:41 And now you've dove in head first here.

58:44 So then you're in the deep end with it.

58:47 - We spent so much time.

58:49 I shouldn't even bring this up, but we did, okay, when we were, whatever,

58:53 I won't tell the whole story 'cause I need to not, but like we did consider like lots of different names

58:58 for this tool and multiple times we considered a name and then it turned out to be a standard library module

59:03 that none of us had ever used.

59:05 Like we wanted to use WAVE, W-A-V-E, but that's a standard library module.

59:10 Yeah, yeah.

59:11 I was like, oh, I had no idea.

59:12 - Is that for working with WAVE audio files?

59:14 Probably it is.

59:15 - Yeah, like WAV files, yeah.

59:17 - Yeah, interesting.

59:18 Yeah, there's a bunch of stuff.

59:19 There's a whole demo reason removing certain things that like, you know, I know it's like a library,

59:25 but some of these things I had never seen.

59:28 - Yeah, well, it's naming tools and packages is a whole special deal.

59:33 And we have half a million packages in PyPI.

59:36 And so how are you gonna not conflict with that?

59:38 Have an interesting name.

59:39 That's not for, I'm for typo squatting.

59:42 - Yeah, exactly.

59:43 - Hard, it's a hard problem.

59:44 - Yeah, I don't even get me started on name stuff.

59:46 Someone actually donated this name to us, which is very kind of them.

59:49 - Oh, that's actually very cool.

59:51 Very cool.

59:52 All right, one other thing I do wanna talk about here, Kanishka says, asks about, you know,

59:58 is there a future where Rye, R-Y-E, and UV go hand in hand, also great work,

01:00:03 but maybe just talk a bit about Rye.

01:00:05 That was by Armin Roenicker, and it kind of had a similar zen as UV, but really different.

01:00:10 - Yeah, so we, yeah, so we're taking over like maintainership of Rye, and we've just been like,

01:00:19 I think I started talking to Armin, like right after Rye got released, which was PyCon last year,

01:00:25 I think it was during PyCon it got released.

01:00:27 And we talked like shortly after, and we just found that like, we were trying to do a lot of the,

01:00:32 we were trying to solve a lot of the same problems, and we had like very similar vision

01:00:35 for what we wanted packaging to be.

01:00:37 But like, we were coming at it from very different angles, like Rye kind of came at it from,

01:00:42 let's solve the Python bootstrapping problem.

01:00:44 So we're gonna ship a Rust tool.

01:00:45 - It's like it's main focus, yeah.

01:00:46 - Yeah, exactly.

01:00:47 And then internally, it was actually using like pip tools, and pip to do installs and resolutions.

01:00:54 And then the thing that, I think the thing that Armin came to realize was like,

01:00:58 if you wanna fulfill this whole vision, you kind of need to like reinvent a lot of those internals.

01:01:03 And meanwhile, like we were building UV, which was like basically those internals.

01:01:07 And I was like, we're gonna put a lot of effort into like building this packaging stack.

01:01:13 And so we kind of found that like, it was just a really, we were trying to get to the same place.

01:01:18 And we were putting in a lot of the engineering investment on building a lot of kind of building blocks.

01:01:23 And we want UV to evolve into something that could like fully replace Rye.

01:01:28 So we want it to evolve in that direction.

01:01:31 And in the meantime, like we're gonna keep maintaining Rye and kind of using it as like a little bit of a test bed

01:01:38 for like experimental things, like Armin added like pytest support to it, for example.

01:01:42 So we're like, we're kind of playing with like, that's meant to be more of an experimental test bed

01:01:47 for like the future that we wanna achieve.

01:01:49 And over time, we're gonna kind of evolve UV up to the point that hopefully it can fully replace it.

01:01:53 And then we can provide a clear migration path for it.

01:01:56 So we're gonna keep maintaining it.

01:01:58 It is our intention for UV to like, to supplant it at some point in the future,

01:02:04 but it'll take us like time for it to get there and be able to do all the things.

01:02:08 But the visions were just so similar that it seemed like it made a lot of sense

01:02:11 to try and consolidate and kind of team up on it.

01:02:14 - Yeah, they do seem pretty similar.

01:02:16 And I can see the direction that you're going in it.

01:02:19 It's gonna make them more similar.

01:02:21 - Yeah, I know it'll take time.

01:02:22 And like, you know, this release of UV is like, it really is like the first release, you know?

01:02:26 It's like, I kind of use some of this stuff as like pretty low level.

01:02:30 Like we wanna build something that feels higher level and more automatic in the future.

01:02:35 But these are kind of like the ability to install and uninstall and resolve packages.

01:02:40 And these were like the fundamental things we needed and need for anything we were gonna do.

01:02:44 And so this goal was really, let's take those and let's put them in a form

01:02:48 that's like immediately useful to people.

01:02:50 - Yeah, for sure.

01:02:51 One more Rye question, then I have other questions.

01:02:54 So UV will replace Rye.

01:02:56 Do you recommend using Rye or UV or what's that side of the story, right?

01:03:01 - Yeah, yeah, yeah.

01:03:02 It kind of depends on what you're doing.

01:03:04 So like Rye uses UV under the hood.

01:03:07 So like Rye uses UV for resolution and installation.

01:03:11 So if you're using Rye, you're using UV.

01:03:13 I like, I say, I consider UV to be like, especially if you're like a company or something,

01:03:19 like I would say UV is production ready for you.

01:03:23 Rye, you're buying into a little bit more of something that's a little bit more experimental.

01:03:29 Like I think Rye is a good fit for like professional projects, hobby projects,

01:03:32 libraries, smaller projects.

01:03:33 I don't know that I would, like you're just buying into more change, I think.

01:03:40 - Yeah.

01:03:41 - And so if you're already--

01:03:41 - So if you're a modern repo, that's got a million lines of code and 110 people on it.

01:03:46 - Yeah, you can certainly try it, but you should know that you're buying

01:03:49 into something experimental is the way I'd put it.

01:03:51 Whereas UV, like you could also view UV as experimental if you want.

01:03:55 Like it's very new, right?

01:03:56 Like we've, we're like when we launched, we had, I mean, I think having issues is actually good

01:04:00 'cause it means people are using your project, but we had like hundreds of issues

01:04:03 and we closed and we closed, we've closed like hundreds and hundreds of issues

01:04:07 since we launched.

01:04:08 - Yeah, you guys have been super, yeah, you've been super responsive on it.

01:04:10 Like you and I've had some exchanges there.

01:04:13 - Yeah, we did.

01:04:14 - And yeah, that's some nice changes I saw going on, but like I said, almost every day--

01:04:19 - It's just getting like way better.

01:04:20 - It's great.

01:04:21 - Yeah, and it's just getting way, way better.

01:04:22 Like that's the thing about developing in private is like, like we just, once we released it,

01:04:27 we finally, we actually had users who could use it and tell us all the things we missed,

01:04:30 tell us all the things we didn't think about.

01:04:31 It's just like every week getting way better.

01:04:33 So like it's getting more and more stable and like I would use it in production for my stuff,

01:04:38 for sure, and I recommend it for production.

01:04:41 But like Rye is just a little bit of a different story.

01:04:44 I think with Rye, you know, it's not like we're gonna shut it down tomorrow

01:04:48 or anything like that.

01:04:49 Like it's gonna be, it's gonna continue to be supported for sure.

01:04:52 But you are, and I think it's branded this way, which is you're are kind of buying

01:04:57 into a little bit of an experimental tool.

01:04:59 - Yeah, also a bit of a workflow.

01:05:01 - Yeah, it's a very opinionated workflow.

01:05:03 - Yeah. - Yeah.

01:05:04 Whereas you'd use more design to kind of slot into existing workflows.

01:05:07 - Sure, it's a little more foundational.

01:05:10 Speaking of which, I really like that, you know, so many of these tools have their own,

01:05:16 their complete own way.

01:05:17 Like I know you're gonna do that, but we're gonna start up our shell and then you're gonna run these three commands

01:05:22 and then we're gonna have our own lock file and we have our own things.

01:05:24 And it's amazing if you drink the Kool-Aid, if you go all in on the tool.

01:05:29 But if you don't, then it's like, okay, well, what is this thing even doing?

01:05:33 It's more in my way than it's helping me, you know, and so on.

01:05:36 So the fact that a lot of this is kind of baking in the pip-tools way of,

01:05:42 there's gonna be this external tool that can manage some of your stuff for you,

01:05:46 but it's not prescribing a workflow, 100% props for that, love it.

01:05:50 - Thanks, yeah, I wanted to build something that, again, I use the word like modular a lot

01:05:55 and I think it can mean different things, but like, Ruff was kind of like this too.

01:05:59 Like in Ruff, you can use it as like just a linter or like just a formatter or both.

01:06:03 And like with UV, like you could use UV like just to create virtual environments

01:06:07 or just to do dependency resolution, but use pip for your installer or something.

01:06:12 Like it's designed to be kind of flexible in how you choose to use it.

01:06:17 And I wanna maintain that, you know, I think we'll start to introduce more opinionated workflows,

01:06:23 but I think that we'll continue to provide this kind of pick and choose model as well.

01:06:29 - Yeah, yeah, I think it's great.

01:06:31 It lines right up with the way I do things.

01:06:33 And also I really like it as both someone who might do presentations either at a conference

01:06:38 or in a course or teaching, because you're not putting, you know, the whole virtual environment stuff

01:06:43 is already such a kind of a large barrier that comes a little early in people's learning path, right?

01:06:49 They're like, I wanna run Python, I wanna run this thing.

01:06:51 Whoa, you don't just install this, you don't just use it.

01:06:55 We're gonna talk about virtual environments.

01:06:56 Like, I don't care about those, I just wanna run it.

01:06:58 Like, but you're gonna need to install something.

01:06:59 So here we go.

01:07:00 Right, adding more workflow and more specific ways of working there, I think while trying to help a lot of times

01:07:06 they end up just adding more friction at the start.

01:07:09 - Yeah, yeah.

01:07:10 And like, I guess my philosophy there is like, I want us to like embrace virtual environments.

01:07:17 I think Rye has this philosophy too, which is like Rye does use virtual environments.

01:07:20 And like virtual environments actually have a lot of, there's a lot of benefits to embracing them.

01:07:24 Like all the editors and such, they're all built around virtual, they all are all built around virtual environment detection

01:07:29 and stuff like that.

01:07:31 But I wanted to feel, I wanted to feel a little, honestly, like it has a really bad reputation,

01:07:36 but I wanted to feel more like node modules, you know?

01:07:38 - Yeah, I agree.

01:07:40 - It just kind of works in your, it just kind of sits in your project and your project just does the right thing.

01:07:44 And I know people make fun of node modules usually for being big, but like, but that's the developer experience I want,

01:07:50 which is you don't think of the virtual environment as this weird other thing.

01:07:53 It's just kind of like the project environment and it just kind of works.

01:07:56 And I think, I think you get that by not like fielding people from it, but abstracting some of it away

01:08:02 for people that don't need to think about it.

01:08:04 - Yeah, there was a, there was an amazing, it's not a joke, but it's, I guess,

01:08:09 something that's a prank that somebody came up with.

01:08:14 Here, I'll put it on the screen.

01:08:15 It's called "When Everything Becomes Too Much," the NPM package chaos of 2024.

01:08:21 And I was just, as you were talking about node modules, this is more of a- - Oh my gosh.

01:08:24 I haven't seen this.

01:08:25 - It's amazing.

01:08:26 So it's more of a statement of like, well, how super interdependent or how many combinatorial or transitive dependencies

01:08:35 does a couple of NPM things have?

01:08:37 Like, for example, I used Tailwind, but there was maybe 50 things in my node module

01:08:43 for just using Tailwind in my project, right?

01:08:45 So anyway, this one is, an NPM user named PatrickJS launched a troll campaign

01:08:51 where a package called everything, it depended on every other NPM package.

01:08:55 So if you, you know, NPM install everything, they literally try to download the repository.

01:09:00 - Yeah, that's kind of amazing.

01:09:03 Wow. - I know.

01:09:04 It's devious, but it's also kind of like, okay, that's something else.

01:09:09 - Yeah, and Python and dependency trees tend to be much, like, shorter, I guess, and like smaller.

01:09:15 Like, you tend to have way fewer dependencies.

01:09:18 They are sometimes like heavier, I guess, 'cause like in Python, it's very common to have lots of native code.

01:09:24 And like, I don't know, like PyTorch, like the PyTorch wheels that you download

01:09:30 when they're zipped are like between 100 and 200 megabytes.

01:09:34 - Wow, okay. - And like, yeah, yeah.

01:09:36 Like all the ML stuff and all the native stuff, like those are like big,

01:09:40 but the number of dependencies tends to be a lot smaller.

01:09:43 - Yeah, I totally agree.

01:09:44 - It's also very common to ship like foundational packages with like no dependencies or very few dependencies,

01:09:49 which is very hard to do in JavaScript.

01:09:52 - Yeah, it is.

01:09:53 It definitely is.

01:09:55 All right, I think we're getting short on time here.

01:09:57 I think I probably should let you go back and knock out another release of UV.

01:10:01 - I do have a new release today.

01:10:02 Okay, thank you. - Awesome.

01:10:03 (laughing)

01:10:04 So Tony, all the audience has been using UV in production for a couple of weeks now.

01:10:08 Also, seems very excited about it.

01:10:10 And also, I have two.

01:10:12 It's an absolute delight.

01:10:14 It hasn't, I know there were certain, yeah, I know there are certain things

01:10:17 that it didn't do like right away, but then it came out and you added them quickly.

01:10:23 I know there was some criticism for you all for developing this in private and then releasing it.

01:10:29 And I just wanna say like, you know, thanks for doing that.

01:10:31 And what's the alternative?

01:10:32 You start with just a blank GitHub repo and people start to say, well, you should do this.

01:10:37 You should be doing that.

01:10:38 Like, we have a vision.

01:10:39 Let us just like get it a little structure in place and then we'll open source it.

01:10:42 Like give us a month, you know?

01:10:45 So I don't know.

01:10:46 I think it's excellent work you're doing.

01:10:48 - I appreciate it.

01:10:49 I appreciate it.

01:10:50 Yeah, yeah.

01:10:51 You know, like I said at the start, it's different this time because anything we release,

01:10:55 like, you know.

01:10:57 - You can work on a ruff for a month and nobody cares until it starts to catch some traction.

01:11:01 Right?

01:11:02 But this is the instant that it hits.

01:11:03 - Yeah, we knew people would at least look at it and at least try it.

01:11:07 And I think, you know, we wanted to make sure that whatever we released, first of all, was good.

01:11:11 And second of all, that we were ready to maintain it.

01:11:13 And I think with packaging too, it's like, there's just a lot of, it's just such a complex space

01:11:19 that like, I wanted to make sure that we had a lot of clarity in the messaging

01:11:23 around what the tool is and what it's not and like what we want it to be and what it isn't yet.

01:11:28 And so I'm really happy with how the launch went and I've really appreciated just all the excitement,

01:11:34 activity, engagement that we've had on the repo.

01:11:37 It's been like, I don't know.

01:11:39 I mean, honestly, it's been a lot of work.

01:11:41 But it's like really, really, no, but it's awesome.

01:11:45 It's like so energizing for me and for the team.

01:11:48 - And to see all the people picking it up and making it the foundation of their projects.

01:11:52 And yeah, it's really cool.

01:11:53 - Yeah, and it's cool.

01:11:54 You know, I guess another, like one other thing that's a little different this time is like,

01:11:58 I talk, I just talked to more people who work on Python tooling at companies now

01:12:02 than I did when I released Ruff, just 'cause over the course of the past year,

01:12:06 I've just met a lot of people and we've just talked about how they're using Ruff,

01:12:09 how they're not.

01:12:10 And so just hearing some of those stories too of how like companies are starting to use it

01:12:14 and like what the blockers are and like how much of a speed up it's providing

01:12:17 has been pretty cool to see too.

01:12:18 So yeah, I know I appreciate it though.

01:12:21 - Yeah, you're welcome.

01:12:21 All right, we'll leave with this final thought from Juan.

01:12:23 I installed 94 libraries in around two seconds.

01:12:25 Incredible. - That's great.

01:12:26 - All right.

01:12:27 (laughing)

01:12:29 All right, well, I'm excited to see where things go and you know, we'll maybe do a follow-up

01:12:32 when you've got some more of the ideas in place.

01:12:37 - Sounds great.

01:12:38 No, it's always a pleasure.

01:12:39 Thanks so much for having me on.

01:12:39 I really appreciate it.

01:12:40 - Yeah, thanks Charlie.

01:12:42 This has been another episode of Talk Python to Me.

01:12:46 Thank you to our sponsors.

01:12:47 Be sure to check out what they're offering.

01:12:48 It really helps support the show.

01:12:51 It's time to stop asking relational databases to do more than they were made for

01:12:55 and simplify complex data models with graphs.

01:12:59 Check out the sample FastAPI project and see what Neo4j, a native graph database can do for you.

01:13:05 Find out more at talkpython.fm/neo4j.

01:13:10 Want to level up your Python?

01:13:12 We have one of the largest catalogs of Python video courses over at Talk Python.

01:13:16 Our content ranges from true beginners to deeply advanced topics like memory and async.

01:13:21 And best of all, there's not a subscription in sight.

01:13:24 Check it out for yourself at training.talkpython.fm.

01:13:27 Be sure to subscribe to the show.

01:13:29 Open your favorite podcast app and search for Python.

01:13:32 We should be right at the top.

01:13:33 You can also find the iTunes feed at /iTunes, the Google Play feed at /play,

01:13:38 and the direct RSS feed at /rss on talkpython.fm.

01:13:42 We're live streaming most of our recordings these days.

01:13:45 If you want to be part of the show and have your comments featured on the air,

01:13:48 be sure to subscribe to our YouTube channel at talkpython.fm/youtube.

01:13:53 This is your host, Michael Kennedy.

01:13:55 Thanks so much for listening.

01:13:56 I really appreciate it.

01:13:57 Now get out there and write some Python code.

01:14:00 (upbeat music)

01:14:18 Here's what's next!

Back to show page
Talk Python's Mastodon Michael Kennedy's Mastodon