WEBVTT

00:00:00.001 --> 00:00:05.920
Have you ever waited around for pip to do its thing while installing packages or syncing virtual environments,

00:00:05.920 --> 00:00:09.280
or even through some higher-level tools such as pip-tools?

00:00:09.280 --> 00:00:14.000
Then you'll be very excited to hear about what just got announced from Astral,

00:00:14.000 --> 00:00:17.480
a PIP-compatible CLI tool called uv.

00:00:17.480 --> 00:00:19.960
It's like pip, but 100 times faster.

00:00:19.960 --> 00:00:24.480
Charlie Marsh from Rough Fame and the founder of Astral is here to dive in.

00:00:24.480 --> 00:00:25.240
Let's go.

00:00:25.740 --> 00:00:31.220
This is Talk Python To Me, episode 453, recorded March 12, 2024.

00:00:31.220 --> 00:00:49.380
Welcome to Talk Python To Me, a weekly podcast on Python.

00:00:49.380 --> 00:00:51.120
This is your host, Michael Kennedy.

00:00:51.120 --> 00:00:58.620
Follow me on Mastodon, where I'm @mkennedy, and follow the podcast using @talkpython, both on fosstodon.org.

00:00:58.620 --> 00:01:03.700
Keep up with the show and listen to over seven years of past episodes at talkpython.fm.

00:01:03.700 --> 00:01:07.440
We've started streaming most of our episodes live on YouTube.

00:01:07.440 --> 00:01:15.020
Subscribe to our YouTube channel over at talkpython.fm/youtube to get notified about upcoming shows and be part of that episode.

00:01:15.500 --> 00:01:18.020
This episode is sponsored by Neo4j.

00:01:18.020 --> 00:01:26.180
It's time to stop asking relational databases to do more than they were made for and simplify complex data models with graphs.

00:01:26.180 --> 00:01:33.020
Check out the sample FastAPI project and see what Neo4j, a native graph database, can do for you.

00:01:33.020 --> 00:01:37.440
Find out more at talkpython.fm/Neo4j.

00:01:38.100 --> 00:01:41.900
And it's also brought to you by us over at Talk Python Training.

00:01:41.900 --> 00:01:46.520
Did you know that we have over 250 hours of Python courses?

00:01:46.520 --> 00:01:47.720
Yeah, that's right.

00:01:47.720 --> 00:01:50.280
Check them out at talkpython.fm/courses.

00:01:50.280 --> 00:01:52.300
Hey, y'all.

00:01:52.300 --> 00:01:55.340
I have a quick announcement before we jump into the conversation with Charlie.

00:01:55.340 --> 00:01:57.880
And sticking with the theme of the episode, I'll keep it quick.

00:01:57.880 --> 00:02:01.440
Over at Talk Python, we just released a new free course.

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

00:02:08.340 --> 00:02:18.940
We end up with a dynamic web app that lets you have a ChatGPT style Q&A with a podcast, guests, and hosts starting from just the RSS feed.

00:02:18.940 --> 00:02:20.320
It's really mind-blowing.

00:02:20.860 --> 00:02:27.620
As a sweet bonus, the course shows you a bunch of hands-on examples of FastAPI, HTMX, Beanie, MongoDB, and more.

00:02:27.620 --> 00:02:28.740
I hope you love it.

00:02:28.740 --> 00:02:32.460
Give it a look as it is 100% free, no strings attached.

00:02:32.460 --> 00:02:38.320
The link is on the episode page, in your podcast player show notes, and at talkpython.fm/courses.

00:02:38.320 --> 00:02:40.840
Hey, Charlie.

00:02:40.840 --> 00:02:41.460
Hey.

00:02:41.460 --> 00:02:42.320
Welcome.

00:02:42.320 --> 00:02:44.300
Yeah, thanks so much for having me back on the show.

00:02:44.300 --> 00:02:45.260
I really appreciate it.

00:02:45.260 --> 00:02:47.880
Yes, it's really great to have you back on the show.

00:02:48.400 --> 00:02:53.720
You and your team are doing awesome work these days and making a big dent in Python.

00:02:53.720 --> 00:02:54.100
Thank you.

00:02:54.100 --> 00:02:54.840
Thank you.

00:02:54.840 --> 00:02:56.460
Hopefully a good dent, I guess.

00:02:56.460 --> 00:02:59.860
Yeah, I guess you could make a good dent or a bad dent.

00:02:59.860 --> 00:03:01.780
But no, I meant that in a good way.

00:03:01.780 --> 00:03:02.920
Definitely in a good way.

00:03:02.920 --> 00:03:03.700
I appreciate it.

00:03:03.700 --> 00:03:04.140
Yeah.

00:03:04.140 --> 00:03:05.800
Yeah, I think excellent work.

00:03:05.800 --> 00:03:12.280
It's really, it's kind of surprising how some of these tools just come in and just catch fire in a way.

00:03:12.280 --> 00:03:16.580
I don't know how you felt about it, but it seemed more than I would have expected.

00:03:16.900 --> 00:03:21.960
I mean, I did not expect your things to be popular, but they became really popular really quickly.

00:03:21.960 --> 00:03:23.340
Yeah.

00:03:23.340 --> 00:03:23.960
Yeah.

00:03:23.960 --> 00:03:30.160
I mean, it was different, you know, with Ruff and with uv, this sort of context around it has been pretty different.

00:03:30.160 --> 00:03:36.520
Because with Ruff, like when I started working on Ruff, no one knew who I was or had any reason to care about what I was doing.

00:03:37.220 --> 00:03:41.000
And the project just grew, you know, grew over time.

00:03:41.000 --> 00:03:47.320
And then I knew that when we were working on uv, like there would just be a lot more of an expectation around like anything we build.

00:03:47.320 --> 00:03:47.880
Yeah.

00:03:47.880 --> 00:03:49.600
The spotlight was already shining, right?

00:03:49.600 --> 00:03:50.160
A little bit.

00:03:50.160 --> 00:03:50.480
Yeah.

00:03:50.480 --> 00:03:50.860
Yeah.

00:03:50.860 --> 00:03:53.740
And that's awesome because it means our stuff gets traction.

00:03:53.740 --> 00:03:55.740
Also, it comes with a lot of responsibility.

00:03:56.060 --> 00:03:59.440
It means anything we release, we're, you know, we're kind of committed to maintaining.

00:03:59.440 --> 00:04:01.220
So, like, yeah.

00:04:01.220 --> 00:04:01.260
Yeah.

00:04:01.260 --> 00:04:01.560
Yeah.

00:04:01.560 --> 00:04:07.300
It's been very interesting, like this kind of release cadence versus what happened with Ruff.

00:04:07.300 --> 00:04:10.720
Well, you have more people behind the scenes helping you out, right?

00:04:10.720 --> 00:04:11.380
I do.

00:04:11.380 --> 00:04:11.760
Yeah.

00:04:11.760 --> 00:04:12.220
Thankfully.

00:04:12.220 --> 00:04:12.760
Yeah.

00:04:12.760 --> 00:04:20.360
Tell us, you know, maybe that's a good place to just kick off our conversation is, you know, we're talking a bit about Ruff for everyone.

00:04:20.360 --> 00:04:24.040
And Ruff was the thing that really launched all of this.

00:04:24.040 --> 00:04:27.000
But you started a company, Astral.

00:04:27.000 --> 00:04:27.560
Yep.

00:04:27.560 --> 00:04:28.840
Got some funding behind it.

00:04:28.840 --> 00:04:29.220
Yep.

00:04:29.220 --> 00:04:30.200
Building awesome tools.

00:04:30.200 --> 00:04:30.660
Yeah.

00:04:30.660 --> 00:04:32.900
Just give people the broad view of your world these days.

00:04:32.900 --> 00:04:33.780
Yeah, totally.

00:04:33.780 --> 00:04:42.020
So, yeah, I started, this all started when I released Ruff probably like a year and a half ago, maybe at this point.

00:04:42.020 --> 00:04:49.860
And at that point, it was really not just a side project for me, but very much an exploratory project.

00:04:49.860 --> 00:04:58.340
Like I was kind of curious about building faster Python tooling, really, and curious about getting better at Rust and all this stuff.

00:04:58.340 --> 00:05:07.460
And Ruff, when I released it, it's, you know, it was a lint or it is a linter, but it kind of brings a lot of different tools together.

00:05:07.460 --> 00:05:16.560
So if you're familiar with like Flategate or Pylent, but also Black, Ruff is designed to kind of bundle all those tools together.

00:05:16.560 --> 00:05:19.140
So it can detect problems with your code.

00:05:19.140 --> 00:05:20.560
It can fix them automatically.

00:05:20.560 --> 00:05:22.680
It can reformat your code.

00:05:23.260 --> 00:05:29.100
So often when we see people like adopting Ruff, they're replacing like 20 or 30 tools with Ruff.

00:05:29.100 --> 00:05:36.720
And, you know, it has, there's a bunch of nice things about it, but ultimately it's very, very fast and hopefully a lot simpler for users.

00:05:36.720 --> 00:05:38.120
Yeah.

00:05:38.120 --> 00:05:39.440
But, go ahead.

00:05:39.440 --> 00:05:44.060
I was going to say, it's really nice that it's just one tool that brings that all together.

00:05:44.060 --> 00:05:45.240
You know, it's not a patchwork.

00:05:45.240 --> 00:05:50.700
Well, here's how we use ISORT and here's how we use Flategate and here's how we use this and here's how we use that, you know?

00:05:50.940 --> 00:05:51.140
Right.

00:05:51.140 --> 00:06:00.480
I think ISORT's a really good example because instead of having an ISORT's a great tool, but instead of having a separate tool to do your import sorting, Ruff Frames import sorting is just a lint rule.

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

00:06:06.760 --> 00:06:14.300
And, you know, Ruff, again, when I released it, it was just a side project and it sort of took off.

00:06:14.300 --> 00:06:25.080
You know, there were, it was originally, you know, I released it in part because I had this thesis that like Python tooling could be much faster and Ruff was meant to evidence that.

00:06:25.360 --> 00:06:30.840
It was meant to be an example of what I saw as like this potential to build really different Python tooling.

00:06:30.840 --> 00:06:40.940
And took off a couple of big projects like FastAPI and such were kind of early adopters and it just grew and grew and grew from there.

00:06:41.560 --> 00:06:47.080
And I started a company, Astral, you know, shortly after based on a lot of these ideas.

00:06:47.080 --> 00:06:54.640
So again, Ruff in this context was meant to be, you know, the goal wasn't necessarily to start a company just based around Ruff.

00:06:54.800 --> 00:07:07.460
The goal was to start a company based around, you know, the ideas behind Ruff, which is, can we build really different Python tooling by, well, it's all written in Rust.

00:07:07.460 --> 00:07:09.440
It's sort of an implementation detail, right?

00:07:09.440 --> 00:07:16.900
But ultimately what we're trying to do is build like really high performance Python tooling, but also tooling that works together really well and simplifies things.

00:07:16.900 --> 00:07:19.020
So tackle, it's not just about performance.

00:07:19.020 --> 00:07:23.840
It's also about tackling a lot of, I guess, what I see as the complexity in Python tooling today.

00:07:24.580 --> 00:07:36.640
And really trying to, I guess, challenge certain status quos and respect others, but challenge some status quos in what it feels like to work with and use Python.

00:07:36.640 --> 00:07:47.500
And so, you know, our focus as a company, you know, right now we're very, very focused on our open source roadmap and our open source tooling.

00:07:47.500 --> 00:07:51.340
So that's Ruff now, uv, which we'll talk about in a bit.

00:07:52.080 --> 00:07:58.200
And these are, you know, MIT licensed, you know, fully open source tools that we build.

00:07:58.200 --> 00:08:08.160
And ultimately our goal is to build and sell paid services that integrate really well with the tooling and are kind of like the natural next thing you need when you're building with Python.

00:08:08.620 --> 00:08:12.400
So, you know, we'll never charge money for like the tools themselves.

00:08:12.400 --> 00:08:14.240
Those remain free, permissively licensed.

00:08:14.240 --> 00:08:19.700
But our goal is to kind of build, you know, imagine you're building with Python, you need to deploy a web server.

00:08:19.700 --> 00:08:22.300
There's a lot of things that you need naturally to do that.

00:08:22.380 --> 00:08:30.420
So for people who are already using our tools, what are the natural next things they need and how can we build really good services on top of the tooling that just integrate with it really well?

00:08:30.420 --> 00:08:32.460
So that's kind of the premise of the company.

00:08:32.460 --> 00:08:34.760
There's like really two focuses to the roadmap.

00:08:34.760 --> 00:08:36.540
It's like the open source and the commercial.

00:08:37.400 --> 00:08:46.020
And our goal is to have an incentive structure where we're just continuously aligned to like invest a ton in the open source and grow it as much as possible in a really natural way.

00:08:46.400 --> 00:08:49.080
So you're not going to do like per line fix pricing.

00:08:49.080 --> 00:08:55.160
You get a million, million line fixes a month free and then no, I think it's an awesome model.

00:08:55.160 --> 00:09:07.540
And, you know, open source 10 years ago, it really looked like it was already super vibrant and super making huge dents in the space.

00:09:07.540 --> 00:09:07.800
Right.

00:09:07.800 --> 00:09:09.920
Really a lot of people adopting it.

00:09:10.040 --> 00:09:14.480
But I think there was kind of a funding side that was a little bit missing.

00:09:14.480 --> 00:09:18.880
I still remember like, you know, buy me a coffee type of links, like send me 10 bucks.

00:09:18.880 --> 00:09:19.580
Yeah.

00:09:19.580 --> 00:09:20.840
If you like this.

00:09:20.840 --> 00:09:22.600
And that's just it's not a job.

00:09:22.600 --> 00:09:26.580
That's hardly a hobby type of thing to get stuff done.

00:09:26.580 --> 00:09:28.840
You can't have a team of people focused on it.

00:09:28.840 --> 00:09:33.260
And it had traditionally really been around kind of a beneficial.

00:09:33.260 --> 00:09:39.920
I need to find a big tech company that's willing to give me sufficient amount of time to work on this project.

00:09:39.920 --> 00:09:42.140
To sort of fund its existence.

00:09:42.140 --> 00:09:47.400
Or maybe I'm a consultant and I'm I create Flask, but I consult on Flask, that type of thing.

00:09:47.400 --> 00:09:47.880
Right.

00:09:47.880 --> 00:09:54.460
And I think it's just super positive to see more direct ways people are making open source successful.

00:09:54.460 --> 00:09:55.600
You know, I think.

00:09:55.600 --> 00:09:56.380
Yeah, I appreciate that.

00:09:56.380 --> 00:09:56.980
I wish.

00:09:56.980 --> 00:09:57.420
Yeah, I think.

00:09:57.420 --> 00:10:02.980
You know, I wish I sort of wish that there were more more good examples of that working.

00:10:02.980 --> 00:10:04.360
There are some for sure.

00:10:05.180 --> 00:10:06.880
You know, for me, it was pretty clear.

00:10:06.880 --> 00:10:08.460
Like it was immediately clear to me.

00:10:08.460 --> 00:10:11.560
I needed to work on a rough full time if I wanted the project to succeed.

00:10:11.560 --> 00:10:20.780
And that's kind of a microcosm of the bigger the bigger challenge, which is like we wanted to build like we really wanted to like professionalize the building of this.

00:10:20.780 --> 00:10:24.360
You know, the work on this project and bring in more people to help build it.

00:10:24.360 --> 00:10:28.680
And so, you know, ultimately, it's not obviously it's not it's not charity.

00:10:28.680 --> 00:10:29.720
It is venture funding.

00:10:29.720 --> 00:10:36.600
And ultimately, we need to build a business, you know, around the tooling to make it, you know, to make it sustainable.

00:10:38.060 --> 00:10:50.660
But, you know, again, for me, I want the incentive structure to be such that like the open source is obviously free, open source, extremely permissively licensed and truly open source.

00:10:50.660 --> 00:10:52.640
Like we have tons and tons of contributors.

00:10:52.640 --> 00:10:54.100
We have a huge community around it.

00:10:55.540 --> 00:11:02.160
And I'm just glad that we've been able to, you know, bring in more people to kind of supercharge the development of it all.

00:11:02.160 --> 00:11:02.740
So, yeah.

00:11:02.740 --> 00:11:07.580
So I guess you talked on you touched on this before, but we're now eight people.

00:11:07.580 --> 00:11:14.840
So we've grown, you know, it was it was I guess a year ago it was just me in March.

00:11:14.840 --> 00:11:20.420
So over the past year, our first two team members joined actually in March of last year.

00:11:20.420 --> 00:11:21.580
So almost exactly a year.

00:11:21.580 --> 00:11:24.760
And, yeah, we're completely distributed.

00:11:25.020 --> 00:11:30.640
So we're, you know, we have people in U.S. Pacific time all the way to Bangalore.

00:11:30.640 --> 00:11:35.200
So we're just, you know, around the like open source.

00:11:35.200 --> 00:11:41.200
We're kind of all over the world and and just building, you know, building all this stuff out in the open.

00:11:41.200 --> 00:11:54.260
It's such a good fit to be a distributed company as an open source with open source roots, because the tools of open source in some degree for software in general, but especially for open source is asynchronous.

00:11:54.500 --> 00:11:55.180
Yeah.

00:11:55.180 --> 00:11:59.520
Semi-connected, you know, kind of the zen of get, but for the way you work.

00:11:59.520 --> 00:11:59.860
Right.

00:12:00.120 --> 00:12:04.240
And it makes it super easy to hire just the most engaged people, regardless.

00:12:04.240 --> 00:12:04.860
Yeah, exactly.

00:12:04.860 --> 00:12:05.240
Yeah.

00:12:05.240 --> 00:12:08.460
The people who are willing to commute to my office in the office park.

00:12:08.460 --> 00:12:09.060
Yeah.

00:12:09.060 --> 00:12:18.400
It was I would be pretty surprised if a single person I've hired would have been willing to move to New York, which is around based.

00:12:19.180 --> 00:12:25.300
So from that perspective, it was a no brainer, which is and actually, you know, multiple people we've hired.

00:12:25.300 --> 00:12:28.500
Our relationship with them started on the repo.

00:12:28.500 --> 00:12:29.620
Yeah.

00:12:29.860 --> 00:12:31.020
InRuff itself.

00:12:31.740 --> 00:12:40.760
And then almost everyone we've hired, we discovered through open source in some way or had some relationship through open source in some way.

00:12:40.760 --> 00:12:41.020
Yeah.

00:12:41.380 --> 00:12:51.320
So, yeah, it's been a really it's very much in it's also very much in the DNA of the company, which is, you know, we actually also intentionally try to hire people who have been maintainers.

00:12:51.320 --> 00:12:51.520
Right.

00:12:51.520 --> 00:12:53.300
And have a lot of experience with that, too.

00:12:53.300 --> 00:12:54.920
We view that as a really important skill.

00:12:55.320 --> 00:12:56.220
Yeah, that's excellent.

00:12:56.220 --> 00:12:59.780
So we talked about Ruff.

00:12:59.780 --> 00:13:03.480
One thing I do want to give a bit of a shout out to is I don't remember.

00:13:03.480 --> 00:13:05.460
I think I found this on Mastodon.

00:13:05.460 --> 00:13:07.560
I can't remember where somebody talked about it.

00:13:07.560 --> 00:13:12.380
But one of the things that Ruff does, one, it changes code, which is awesome.

00:13:12.380 --> 00:13:14.400
I love your Ruff format story.

00:13:14.400 --> 00:13:16.580
But it also just tells you, hey, this could be better.

00:13:16.580 --> 00:13:17.820
You're violating PEP 8.

00:13:17.820 --> 00:13:21.620
You're violating this other convention or even a security thing.

00:13:21.620 --> 00:13:21.840
Right.

00:13:21.980 --> 00:13:26.720
But the why is the why of that, I think, requires a little bit of experience.

00:13:26.720 --> 00:13:32.820
Like, why should I use this kind of loop or that kind of comprehension over another?

00:13:32.820 --> 00:13:33.400
Right.

00:13:33.400 --> 00:13:37.300
It's people told me that who are much better have been doing this longer.

00:13:37.300 --> 00:13:38.100
I shouldn't do it.

00:13:38.100 --> 00:13:38.820
Why?

00:13:38.820 --> 00:13:42.680
When you have when you have 700 rules, there's a lot of why.

00:13:42.680 --> 00:13:52.940
And so you guys came up with this thing at docs.astral.sh slash rules, put in links that literally for each one of these has like a little example.

00:13:52.940 --> 00:13:57.440
And what is good and what is bad and when you should use it and so on.

00:13:57.440 --> 00:13:59.300
You want to tell people about this a bit?

00:13:59.300 --> 00:13:59.900
I think it's a mess.

00:13:59.900 --> 00:14:00.540
Yeah, totally.

00:14:00.760 --> 00:14:04.020
So we didn't have, I mean, we obviously didn't have this when we started the project.

00:14:04.020 --> 00:14:08.060
And then we accumulated a lot of rules.

00:14:08.060 --> 00:14:12.240
Like, when we decided to add this, I think we already had like hundreds of rules.

00:14:12.240 --> 00:14:20.060
And the motivation for the format really comes from Clippy, which is the linter used in Rust.

00:14:20.580 --> 00:14:21.020
Okay.

00:14:21.020 --> 00:14:24.580
And they have really, Rust in general has a really good documentation culture.

00:14:24.580 --> 00:14:27.720
And Clippy has this nice format, very similar to ours.

00:14:27.720 --> 00:14:34.580
We've made some adjustments, but it's pretty similar around how you document lint rules, like what's the motivation and giving examples.

00:14:34.580 --> 00:14:37.300
And so we were like, all right, let's, we want to do this.

00:14:37.300 --> 00:14:46.580
And we just over a very long period of time and a lot of contributors contributed on this documentation, but it took like six months or something probably to document it.

00:14:46.580 --> 00:14:49.660
And now, yeah, now we can, now we require it for all rules.

00:14:49.660 --> 00:14:53.520
So it's much easier to add going forward, but it was a huge effort to add this.

00:14:53.520 --> 00:14:59.980
And, you know, some of the explanations too are very extensive and detailed with lots of references.

00:14:59.980 --> 00:15:01.200
Yeah.

00:15:01.200 --> 00:15:01.840
Yeah.

00:15:01.840 --> 00:15:02.100
Yeah.

00:15:02.100 --> 00:15:07.040
I pulled the one up for iSort, unsorted imports, which is error i001.

00:15:07.040 --> 00:15:13.420
And it also talks about whether it can automatically fix it, what this does, why is it bad?

00:15:13.420 --> 00:15:20.140
So it says things like consistency is good, use a common convention for imports to make your code more readable and idiomatic or Pythonic.

00:15:20.140 --> 00:15:20.380
Yep.

00:15:20.380 --> 00:15:22.760
And it just gives an example of bad, good.

00:15:22.760 --> 00:15:24.040
Right, right.

00:15:24.040 --> 00:15:25.200
I think that's nice.

00:15:25.200 --> 00:15:25.820
Yeah.

00:15:25.820 --> 00:15:28.660
And, you know, we've started to put more stuff in here over time too.

00:15:28.660 --> 00:15:36.640
Like whether, like in some cases we let users apply automatic fixes that aren't completely safe, like by opting in.

00:15:36.640 --> 00:15:39.600
Like it might change the meaning of your code and you kind of need to be careful.

00:15:39.800 --> 00:15:43.760
And so over time we've started to document that here too, like rules that have unsafe fixes.

00:15:43.760 --> 00:15:44.260
Why?

00:15:44.260 --> 00:15:47.460
Like in what case might it break your code and what should you look out for?

00:15:47.460 --> 00:15:55.300
So, yeah, we want it to be a tool with really good, like we're kind of inspired by Rust in this way.

00:15:55.300 --> 00:16:01.320
Because Rust has a really good documentation culture and also the Rust like compiler itself has really good error messages.

00:16:02.020 --> 00:16:06.280
It's sort of famous for that, like when your code doesn't work, it's really good at telling you why.

00:16:06.280 --> 00:16:09.660
It doesn't always get it right, but it has famously good error messages.

00:16:09.660 --> 00:16:19.400
And that's something that we try and channel too, to like when we make changes to configuration, like just putting extra effort into trying to make like those, those like error messages and those hints helpful.

00:16:19.400 --> 00:16:20.680
But yeah, it's a lot of work.

00:16:20.680 --> 00:16:21.480
So I appreciate you.

00:16:21.480 --> 00:16:22.760
I appreciate that you called it out.

00:16:23.860 --> 00:16:29.720
I'm sure it looks like a lot of work, but it's one of those things that's, where else are you going to get this knowledge, right?

00:16:29.720 --> 00:16:34.540
I mean, I know you can go search for one at a time, but in this aggregates is really good.

00:16:34.540 --> 00:16:35.220
Right, right, right.

00:16:37.220 --> 00:16:40.560
This portion of Talk Python To Me is brought to you by Neo4j.

00:16:40.560 --> 00:16:42.500
Do you know Neo4j?

00:16:42.500 --> 00:16:45.240
Neo4j is a native graph database.

00:16:45.240 --> 00:16:50.100
And if the slowest part of your data access patterns involves computing relationships,

00:16:50.100 --> 00:16:57.340
why not use a database that stores those relationships directly in the database, unlike your typical relational one?

00:16:57.340 --> 00:17:04.020
A graph database lets you model the data the way it looks in the real world, instead of forcing it into rows and columns.

00:17:04.460 --> 00:17:11.640
It's time to stop asking a relational database to do more than they were made for and simplify complex data models with graphs.

00:17:11.640 --> 00:17:16.720
If you haven't used a graph database before, you might be wondering about common use cases.

00:17:16.720 --> 00:17:17.600
You know, what's it for?

00:17:17.600 --> 00:17:19.000
Here are just a few.

00:17:19.000 --> 00:17:20.120
Detecting fraud.

00:17:20.120 --> 00:17:21.640
Enhancing AI.

00:17:21.640 --> 00:17:23.440
Managing supply chains.

00:17:23.440 --> 00:17:26.320
Gaining a 360-degree view of your data.

00:17:26.320 --> 00:17:29.680
And anywhere else you have highly connected data.

00:17:29.680 --> 00:17:34.380
To use Neo4j from Python, it's a simple pip install.

00:17:34.380 --> 00:17:35.140
Neo4j.

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

00:17:42.260 --> 00:17:47.280
Find it in their docs or search GitHub for Neo4j Movies Application Quick Start.

00:17:47.280 --> 00:17:51.460
Developers are solving some of the world's biggest problems with graphs.

00:17:51.460 --> 00:17:52.660
Now it's your turn.

00:17:52.660 --> 00:17:56.960
Visit talkpython.fm/Neo4j to get started.

00:17:57.180 --> 00:18:00.900
That's talkpython.fm/Neo4j.

00:18:00.900 --> 00:18:05.000
Thank you to Neo4j for supporting Talk Python To Me.

00:18:06.320 --> 00:18:09.300
So Ruff will fix a lot of these things for you.

00:18:09.300 --> 00:18:14.820
And one of the things that I like to do is I just have it integrated into my editor these days.

00:18:14.820 --> 00:18:21.000
So both with PyCharm and with VS Code, if I just say format this document, that's a Ruff format.

00:18:21.000 --> 00:18:21.660
Nice.

00:18:21.660 --> 00:18:22.920
Yeah, yeah.

00:18:23.000 --> 00:18:25.460
So we have a VS Code extension.

00:18:25.460 --> 00:18:30.660
And it supports formatting, autofixing, all that kind of stuff.

00:18:30.660 --> 00:18:35.380
The PyCharm one's a third-party one, right?

00:18:35.380 --> 00:18:36.680
Someone else decided to make that.

00:18:36.840 --> 00:18:39.640
Yeah, the JetBrains one is by Huda.

00:18:39.640 --> 00:18:45.160
And it's, yeah, that's like a community extension.

00:18:45.160 --> 00:18:53.260
We're considering doing our own at some point because there's a lot of demand for, obviously, we have a lot of users who use the JetBrains stuff.

00:18:53.260 --> 00:18:54.400
I mean, I use it.

00:18:54.400 --> 00:18:58.060
So we may do our own at some point, but there's a community-maintained one right now.

00:18:58.060 --> 00:19:02.040
And that's based on, we have sort of like a language server.

00:19:02.040 --> 00:19:08.320
So there's kind of like an underlying piece of technology that wraps rough, that powers all of these editor integrations.

00:19:08.320 --> 00:19:13.220
So you can also use that from like NeoVim or Sublime Text or Emacs.

00:19:13.220 --> 00:19:15.580
All of those editors support the LSP.

00:19:15.580 --> 00:19:20.620
And so you can actually, it's the same thing that powers the VS Code extension.

00:19:20.620 --> 00:19:23.440
Just that's wrapped in some VS Code specific stuff.

00:19:23.440 --> 00:19:25.420
But it's the same piece of technology.

00:19:26.920 --> 00:19:34.320
We're actually rewriting that right now to make it sort of like more natively integrated into Ruff, which will let us do some cool things.

00:19:34.320 --> 00:19:41.860
So it should get like actually significantly better, I think, over the course of this year because it's becoming more and more of a priority for us.

00:19:41.860 --> 00:19:42.640
Yeah, cool.

00:19:42.640 --> 00:19:44.900
The whole LSP thing is pretty interesting.

00:19:44.900 --> 00:19:47.900
I think it's really opened up a lot of editors being better.

00:19:47.900 --> 00:19:49.680
Yeah, it has.

00:19:49.680 --> 00:19:55.540
And it made it, like from our perspective, it made it way easier to build like editor integrations.

00:19:55.780 --> 00:20:01.600
Because we just built an LSP and then it like works for like everyone, almost.

00:20:01.600 --> 00:20:03.260
Yeah.

00:20:04.020 --> 00:20:11.320
Like the JetBrains stuff, it does support the LSP, but I think only in the paid version, not in the community version.

00:20:11.320 --> 00:20:13.220
So like there's some limitations around it.

00:20:13.220 --> 00:20:20.600
But in general, like if you support the LSP, like it's actually very easy to build editor integrations that work with everyone, which is like super, super useful.

00:20:20.600 --> 00:20:21.260
Yeah.

00:20:21.260 --> 00:20:26.020
Instead of rebuilding your own integration for every single thing, which is not fun.

00:20:26.240 --> 00:20:27.020
Yeah, it's a lot.

00:20:27.020 --> 00:20:27.700
All right.

00:20:27.700 --> 00:20:31.400
Well, let's talk about the main project here.

00:20:31.400 --> 00:20:35.360
The main reason for being here today is uv.

00:20:35.360 --> 00:20:37.260
Tell people what uv is.

00:20:37.260 --> 00:20:40.460
This is your next big project, next big tool.

00:20:40.460 --> 00:20:40.840
Yes.

00:20:40.840 --> 00:20:41.440
Yeah.

00:20:41.440 --> 00:20:46.180
UV, we released uv a little under a month ago.

00:20:47.180 --> 00:20:59.860
And this is something that I've wanted to do, like basically since we started the company, I wanted to start, I thought there was an opportunity to build some really interesting tooling in Python packaging.

00:21:00.420 --> 00:21:03.220
And uv is kind of the first milestone in that.

00:21:03.220 --> 00:21:17.660
So uv, in its current form, it's designed as a sort of drop-in alternative to pip, pip-tools, like if you use pip compile, pip sync, and virtualenv.

00:21:17.660 --> 00:21:21.220
So it takes those three tools and tries to bundle them into one.

00:21:22.820 --> 00:21:32.720
And so it can do things like, you know, given a set of input requirements, generate a requirements.txt file similar to what you'd get from pip compile.

00:21:32.720 --> 00:21:39.820
It can, you know, you can do uv pip install-r requirements.txt, uv pip install black.

00:21:40.820 --> 00:21:53.380
So it's really intended right now to be sort of, you know, it won't always, we don't support absolutely 100% of what pip does, but it's, we try to be pretty close.

00:21:53.380 --> 00:22:07.620
And so in many cases, the intention is that people can basically drop in uv in their project that uses pip today and get, in many cases, like very, very significant performance improvements.

00:22:07.720 --> 00:22:14.700
So similar to Ruff, like some of the goals we had for this project were one, it should be very, very fast.

00:22:14.700 --> 00:22:18.200
And uv, it's really fast.

00:22:18.200 --> 00:22:25.940
In particular, there's like a benchmarks.md in here, actually, if you want to click on that.

00:22:25.940 --> 00:22:27.540
Now scroll up.

00:22:27.540 --> 00:22:28.380
Does that do it?

00:22:28.380 --> 00:22:29.980
Oh yeah, that works too, I guess.

00:22:29.980 --> 00:22:31.360
That was smart of me.

00:22:31.360 --> 00:22:41.800
Yeah, so it's really, really fast, especially if you've already have, if you're, if you have things cached, which is pretty common.

00:22:41.800 --> 00:22:51.340
So like often on your machine, when you're doing like pip install-r, whatever, a lot of those packages, you've probably installed them at least like once before on your machine.

00:22:52.400 --> 00:22:57.920
Or maybe you deleted your virtual environment and you're recreating it with the exact same dependencies or something like that.

00:22:57.920 --> 00:23:02.160
UV is like very, very well optimized for that case.

00:23:02.160 --> 00:23:08.200
So if you have a package that you're installing multiple times, like the installation is effectively free.

00:23:08.200 --> 00:23:12.340
And it's also a lot more like disk space efficient.

00:23:12.540 --> 00:23:20.000
We use kind of like, we store all of them in one place and kind of copy them into your virtual environment so that you don't have like many, many different copies of the package too.

00:23:20.000 --> 00:23:36.440
So this was all kind of taking techniques and inspiration from like other ecosystems and other package managers and kind of molding them to fit Python's model for how packaging and dependencies work and all the specifications.

00:23:37.320 --> 00:23:44.640
And so again, the end result is like you, you know, installing into a virtual environment, a package that you've already installed before is basically free.

00:23:44.640 --> 00:23:49.600
And yeah, a lot of these things are just like way, way, way faster.

00:23:49.600 --> 00:23:52.640
Similar to rough, like dramatically faster.

00:23:52.640 --> 00:23:53.100
Yeah.

00:23:53.100 --> 00:23:53.440
Yeah.

00:23:53.440 --> 00:23:54.280
And similar to radically.

00:23:54.280 --> 00:24:01.180
And I think, you know, it's worth pointing out that like on one hand, we all have an extra 10 seconds, right?

00:24:01.180 --> 00:24:03.220
Or of course, whatever.

00:24:04.220 --> 00:24:09.920
But in the aggregate, all of these things are just like little paper cuts over your day, you know?

00:24:09.920 --> 00:24:11.000
And so, yeah, sure.

00:24:11.000 --> 00:24:15.340
I can format the code and I could use something nice and sure if it takes 20 seconds.

00:24:15.340 --> 00:24:15.700
Okay.

00:24:15.700 --> 00:24:19.660
But then you stop running it because it's kind of a hassle and you're just, you're in your flow.

00:24:19.660 --> 00:24:21.940
And this is kind of the same way.

00:24:21.940 --> 00:24:28.260
It's like, oh, I want to maybe see if there's a new, some new packages for this project as I'm sitting down to work on it.

00:24:28.260 --> 00:24:37.660
Like, okay, well, wait for a pip compile to run and you wait and you wait and then like, okay, now it's done the onto the development version and you wait and you wait.

00:24:37.660 --> 00:24:40.720
And like, you know, it's just some of these things that are instant.

00:24:40.720 --> 00:24:45.400
You just ask the question more and it just doesn't break your train of thought, you know?

00:24:45.400 --> 00:24:45.880
Totally.

00:24:46.320 --> 00:24:50.860
I think there's like maybe like three different things that come to mind here when we think about performance.

00:24:50.860 --> 00:24:52.180
Because like, yeah, okay.

00:24:52.180 --> 00:24:58.740
In this case, like it may not seem to change your life if you're going from one second to, you know, 50 milliseconds.

00:24:58.740 --> 00:25:00.860
But I think three things come to mind.

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

00:25:07.380 --> 00:25:15.620
And so if you're at a company and you have like a big monorepo with like a bunch of different sub projects, they all have requirements files and you want to bump a dependency.

00:25:15.620 --> 00:25:22.080
That can be like, at that point you're talking like 15 plus minutes for a command.

00:25:22.080 --> 00:25:28.320
And so like for the larger the project gets, obviously the more performance matters and the more it helps out.

00:25:28.320 --> 00:25:30.360
And we're trying to build tooling that can basically scale.

00:25:30.540 --> 00:25:35.580
I don't know about like to arbitrarily large projects, but like two large projects and useful for companies too.

00:25:35.580 --> 00:25:47.980
You know, the other thing I'd say is I think there's something that happens like when tools, when you make something like way faster, it just changes a lot of the ergonomics around what it's like to do things.

00:25:47.980 --> 00:25:57.540
And so, you know, in this case, like, okay, so installing into a virtual environment, a package that you've already installed before is free now.

00:25:57.540 --> 00:25:59.280
And so how does that change things?

00:25:59.280 --> 00:26:00.360
It's nearly instant.

00:26:00.360 --> 00:26:01.480
So how does that change things?

00:26:01.480 --> 00:26:01.640
Right.

00:26:01.640 --> 00:26:07.360
So that means like if you mess up your virtual environment and have to delete it and recreate it, it doesn't, it doesn't cost you anything.

00:26:07.360 --> 00:26:09.060
It's totally, it's totally ephemeral.

00:26:09.060 --> 00:26:11.020
You can throw it away and recreate it at any time.

00:26:11.020 --> 00:26:18.640
And like, that's just like a different, like, it sounds small, but that's kind of like a different relationship to a virtual environments than before where it's like, okay, I created the virtual environment now.

00:26:18.640 --> 00:26:19.740
Oh no, my virtual environment.

00:26:19.740 --> 00:26:20.260
So I messed up.

00:26:20.260 --> 00:26:21.000
I got to recreate it.

00:26:21.000 --> 00:26:25.320
Like we want to just change a lot of the dynamics around some of those like abstractions.

00:26:25.320 --> 00:26:32.600
And then the other thing is this performance budget or this, if you think of performance, like a budget, this buys us a lot of room.

00:26:33.000 --> 00:26:41.320
And so like the fact that we are so fast on some of these things means that we can do things that otherwise might be like prohibitively slow.

00:26:41.320 --> 00:26:44.100
And this is more sort of forward looking and for the future.

00:26:44.100 --> 00:27:01.900
Like one thing that we're thinking about a lot right now is this idea of like resolving Python dependencies for many platforms because it's a little bit complicated, but you know, pip compile and pip and uv, they're really designed to only work on like the current Python platform and the current Python that you're using.

00:27:01.900 --> 00:27:22.240
So if you're on like macOS and you run pip compile, it will give you dependencies that are correct for like macOS and your current Python version, but they might be wrong on Windows because Python and Python, you can have dependencies that vary based on things like the current Python version or the current operating system.

00:27:23.240 --> 00:27:26.320
And so one example would be uvloop, right?

00:27:26.320 --> 00:27:27.560
For people trying to speed up.

00:27:27.560 --> 00:27:28.760
I think it doesn't work on Windows.

00:27:28.760 --> 00:27:30.580
It doesn't work at all on Windows.

00:27:30.580 --> 00:27:31.020
That's right.

00:27:31.020 --> 00:27:31.840
And so, yeah.

00:27:31.840 --> 00:27:32.940
So that's a very common one.

00:27:32.940 --> 00:27:33.620
Yeah.

00:27:34.360 --> 00:27:48.600
And it is, I think, very common that this is a very common thing, like on like lots of really, really popular packages have these kinds of markers, these what are called markers, which basically makes the dependencies conditional based on the current Python.

00:27:49.600 --> 00:28:05.040
And so, you know, like again, like in pip and pip-tools, uv right now just locks for the current Python poetry and I think PDM, but poetry for sure does this very interesting thing where they actually try to lock.

00:28:05.040 --> 00:28:07.980
They try to resolve for like all possible platforms.

00:28:09.260 --> 00:28:17.920
And that's something, it's really convenient because it means that like you kind of do one lock and then any user anywhere can like use that and it works.

00:28:17.920 --> 00:28:24.460
And it's kind of like guaranteed to be right as opposed to maybe it doesn't work on Windows or whatever else.

00:28:24.460 --> 00:28:29.920
And so we're pretty interested in like that, adding that behavior and that's going to be like more expensive.

00:28:30.440 --> 00:28:41.160
And so if we have something that's really fast right now, it kind of like opens up a design space of interesting things we can do to solve that problem while still being, you know, very fast.

00:28:41.160 --> 00:28:44.160
So that's kind of how I think about performance.

00:28:44.160 --> 00:28:50.880
Like I think it's, I think people like a little bit underrate how much of an impact it can have on even small interactions.

00:28:50.880 --> 00:28:55.360
Because once you try something that's much faster, it's often hard to go back to the other thing.

00:28:55.360 --> 00:28:59.340
But I'm glad you've had that experience at least.

00:28:59.340 --> 00:29:00.220
Yeah, absolutely.

00:29:00.580 --> 00:29:02.180
A couple of interesting comments.

00:29:02.180 --> 00:29:07.980
Danny says, if it takes 10 seconds, I go to triage that issue on GitHub and come back five minutes later, right?

00:29:07.980 --> 00:29:10.360
Like that's kind of where I was getting at with the flow stuff.

00:29:10.360 --> 00:29:11.320
It's like, okay, I'm ready.

00:29:11.320 --> 00:29:15.000
Mind wonders and you're kind of like starting over.

00:29:15.000 --> 00:29:16.160
Yeah.

00:29:16.160 --> 00:29:19.360
And then Henry out in the audience also says, hey, Henry.

00:29:19.360 --> 00:29:29.440
Also, this doing things so quickly, it encourages good environment usage because if doing things the right way is just as easy and as fast as doing it the wrong way, you might as well do it the right way.

00:29:29.440 --> 00:29:30.120
That's a nice thought.

00:29:30.120 --> 00:29:30.940
That's a nice thought.

00:29:30.940 --> 00:29:31.120
Yeah.

00:29:31.120 --> 00:29:31.620
Yeah.

00:29:31.620 --> 00:29:32.220
It is.

00:29:32.280 --> 00:29:32.720
Yeah.

00:29:32.720 --> 00:29:39.320
I think there are certain things though where we aren't any faster.

00:29:39.900 --> 00:29:44.360
And I'm interested in thinking about those and what we can do about them.

00:29:44.360 --> 00:29:53.600
The most obvious one is in Python, sometimes when you install a dependency, you might have to build it from source.

00:29:53.600 --> 00:30:00.820
And in Python, you often are installing things like NumPy, which includes some native code.

00:30:01.360 --> 00:30:05.600
And so actually turning that into something that your system can run is kind of expensive.

00:30:05.600 --> 00:30:14.620
And you typically don't have to think about this with NumPy because they ship what are called wheels, which are kind of like these pre-compiled artifacts.

00:30:16.000 --> 00:30:19.180
But not all packages ship wheels.

00:30:19.180 --> 00:30:21.640
You could be on a platform that doesn't have a wheel.

00:30:21.640 --> 00:30:33.000
For a variety of reasons, you might get the raw NumPy source code and then have to compile it down into a build distribution.

00:30:33.740 --> 00:30:41.460
And for us, if we get into that situation, it's not going to be any faster because we still have to build the thing from source.

00:30:41.460 --> 00:30:41.800
Yeah.

00:30:41.800 --> 00:30:42.500
Just like this.

00:30:42.500 --> 00:30:44.320
That's the slowest part of the whole process.

00:30:44.320 --> 00:30:44.660
Yeah.

00:30:44.660 --> 00:30:51.920
And so there are some cases and some bottlenecks where I'm kind of thinking about how could we do even better there.

00:30:51.920 --> 00:30:55.340
And there are actually things that are changing in the standards that have made this a little easier.

00:30:55.340 --> 00:30:58.280
There's this new thing called metadata 2.2.

00:30:58.280 --> 00:30:59.180
Sounds cool.

00:30:59.180 --> 00:30:59.680
I know.

00:31:00.460 --> 00:31:03.920
It basically lets you read the metadata.

00:31:03.920 --> 00:31:05.400
You thought you liked metadata 2.1.

00:31:05.400 --> 00:31:05.760
Yeah.

00:31:05.760 --> 00:31:06.860
Yeah.

00:31:06.860 --> 00:31:09.340
We're actually on 2.3 now.

00:31:09.340 --> 00:31:11.600
I'm just kidding.

00:31:11.600 --> 00:31:18.880
But the point of that is it's a standard that makes it so you don't have to build the thing as often.

00:31:18.880 --> 00:31:24.280
If you just want to know the metadata of NumPy, for example, you may no longer need to build it.

00:31:24.280 --> 00:31:25.160
And before you did.

00:31:25.160 --> 00:31:27.920
And so the standards are moving in a helpful direction here.

00:31:28.040 --> 00:31:33.320
But I just thought I'd call it out because like the source distribution, there are cases where it won't be faster.

00:31:33.320 --> 00:31:35.420
And I'm pretty interested in those.

00:31:35.420 --> 00:31:37.300
But people should know that they also exist.

00:31:37.300 --> 00:31:40.520
There's also, it's not just time.

00:31:40.520 --> 00:31:42.980
There's also security issues around that, right?

00:31:42.980 --> 00:31:50.940
If things are still based on building source from source and then running the setup pie to see what the metadata is.

00:31:50.940 --> 00:31:57.520
It's both slow and also potentially running arbitrary code just to install a thing, which can make you, I mean, I don't know.

00:31:57.520 --> 00:32:01.860
Rarely has anything gone wrong with just installing running arbitrary code off the internet.

00:32:01.860 --> 00:32:03.700
But sometimes it could go wrong.

00:32:03.700 --> 00:32:04.280
Yeah.

00:32:04.280 --> 00:32:11.420
It would be nice to get to a world where that's not required or at least for dependency resolution.

00:32:11.420 --> 00:32:13.660
And like the standards are moving in that direction.

00:32:13.660 --> 00:32:14.540
Yeah, exactly.

00:32:14.540 --> 00:32:16.560
I mean, you might, if you're going to use it, you're going to have to get it.

00:32:16.560 --> 00:32:20.320
But if you just want to know, well, what versions do I need to put these two things together?

00:32:20.320 --> 00:32:21.360
You shouldn't have to do that.

00:32:21.360 --> 00:32:21.900
Yeah, exactly.

00:32:22.080 --> 00:32:28.680
Because today for NumPy, for example, if you didn't have a wheel, you would have to run some arbitrary code to ask it for its dependencies.

00:32:28.680 --> 00:32:29.760
Yeah, exactly.

00:32:29.760 --> 00:32:32.740
Well, let's talk about some of the usages here.

00:32:32.740 --> 00:32:35.020
Let's see some more interesting comments in the chat.

00:32:35.020 --> 00:32:35.920
I'll get back to them.

00:32:35.920 --> 00:32:40.640
First of all, you know, is it like Highlander the movie?

00:32:40.640 --> 00:32:42.220
Should there just be one?

00:32:42.220 --> 00:32:47.360
Is UPy a thing that I put into, say, my requirements file if I want to use it?

00:32:47.360 --> 00:32:49.840
Or do I install it just once for my machine?

00:32:49.840 --> 00:32:51.660
Like, what's the scale?

00:32:51.940 --> 00:32:52.520
UV.

00:32:52.520 --> 00:32:54.240
So there's a lot of different ways.

00:32:54.240 --> 00:32:56.080
You can, there's a lot of different ways to install it.

00:32:56.080 --> 00:32:58.280
You definitely can install it into a virtual environment.

00:32:58.280 --> 00:33:03.040
My general recommendation would be to install it on your machine once.

00:33:03.040 --> 00:33:09.780
Because an interesting thing about uv is you don't need Python to install it.

00:33:09.780 --> 00:33:13.080
And it doesn't have, you need to have Python on your machine.

00:33:13.080 --> 00:33:19.180
Because we need to be able to, for example, build source distributions or know where to install the thing.

00:33:19.180 --> 00:33:19.500
Right?

00:33:19.540 --> 00:33:22.000
We have to install into a virtual environment somewhere.

00:33:22.000 --> 00:33:26.180
And so you have to have Python installed on your machine.

00:33:26.180 --> 00:33:27.780
But uv does not depend on Python.

00:33:27.780 --> 00:33:33.840
So like it can install into arbitrary virtual environments or into arbitrary other Python interpreters.

00:33:33.840 --> 00:33:41.800
So that's why we generally recommend using like these standalone installers that we have at the top of this snippet on the screen.

00:33:41.800 --> 00:33:45.080
They're like the curl and the PowerShell invocations.

00:33:45.520 --> 00:33:50.260
Those will install a single binary on your machine that's uv.

00:33:52.160 --> 00:34:00.120
And from there, you can use uv to install into virtual environments that it creates, to install into your system Python, to do whatever.

00:34:00.840 --> 00:34:11.040
So like I would say most people, based on the statistics, based on our download statistics, most people still install uv with pip, which makes sense, which is not that surprising to me.

00:34:11.040 --> 00:34:15.880
But I would generally recommend having like one uv install on your machine.

00:34:15.880 --> 00:34:19.260
Although if you do install into a virtual environment, like that's also totally fine.

00:34:19.360 --> 00:34:20.560
Like nothing's going to go wrong.

00:34:20.560 --> 00:34:26.060
It's just not completely necessary because a single uv can already install into that virtual environment.

00:34:26.060 --> 00:34:26.720
Right.

00:34:26.720 --> 00:34:29.040
You're never going to import uv.

00:34:29.040 --> 00:34:29.580
No.

00:34:29.580 --> 00:34:32.700
I mean, you might, but in general, people are not going to.

00:34:32.700 --> 00:34:34.600
I think you can.

00:34:34.600 --> 00:34:36.580
I'm trying to think what would happen.

00:34:36.580 --> 00:34:42.220
It's not like things like pie tests and other things.

00:34:42.220 --> 00:34:48.880
A lot of times there could be just one of those, but then you want to use fixtures and you need to import something out.

00:34:48.880 --> 00:34:52.380
So then it really needs to be in the virtual environment and accessible like a library.

00:34:52.380 --> 00:34:57.300
But this is just something you run maybe even before your codes, before your virtual environment exists.

00:34:57.300 --> 00:34:57.580
Right.

00:34:57.580 --> 00:35:01.580
Like it is, it really kind of does ideally exist outside of it, I think.

00:35:01.580 --> 00:35:01.960
Yeah.

00:35:01.960 --> 00:35:03.140
Ideally it exists outside of it.

00:35:03.140 --> 00:35:07.620
And there are some cases where you'd want to install it within the virtual environment, but ideally it exists outside of it.

00:35:07.620 --> 00:35:15.820
The other thing that's nice about using the standalone installers, like at the top here, is soon we're going to ship like a self-update command.

00:35:16.120 --> 00:35:20.400
So you can do like uv self-update and it will update uv to the latest version.

00:35:20.920 --> 00:35:25.640
And we can't really support that if you install it with a different package manager, like pip or brew.

00:35:25.640 --> 00:35:27.760
Those have their own upgrade commands, obviously.

00:35:27.760 --> 00:35:35.260
But like if you install it with our installer, then like we can control the upgrades and stuff like that and provide some other features.

00:35:36.180 --> 00:35:41.300
So that's generally what we recommend, but obviously we're always going to support like installing with pip and stuff too.

00:35:41.300 --> 00:35:41.700
Yeah.

00:35:41.700 --> 00:35:44.520
I'm all about pipX these days.

00:35:44.520 --> 00:35:45.520
I really like...

00:35:45.520 --> 00:35:46.200
Yeah, we're pipX.

00:35:46.200 --> 00:35:46.540
That's mine.

00:35:46.540 --> 00:35:48.020
Yeah, yeah.

00:35:48.020 --> 00:35:53.900
PipX really, you know, you can just say, kind of like brew, you can say upgrade all my Python CLI tools.

00:35:53.900 --> 00:35:55.360
PipX upgrade all.

00:35:55.580 --> 00:35:55.980
Yeah, yeah.

00:35:55.980 --> 00:35:57.420
Yeah, yeah, yeah.

00:35:57.420 --> 00:36:02.900
I find rough and uv is just, you guys are moving super fast and there's frequently an update.

00:36:02.900 --> 00:36:04.760
There are often updates, yeah.

00:36:04.760 --> 00:36:05.880
Yeah.

00:36:06.580 --> 00:36:18.480
Yeah, and then, you know, the uv interface, like it's meant to be pretty familiar to, or it's meant to be, I guess, hopefully very familiar to people who have used, who are already using pip and other tools.

00:36:18.480 --> 00:36:22.220
And so like UVVM creates a virtual environment.

00:36:22.220 --> 00:36:27.180
And then there's, we have this sort of pip subcommand.

00:36:27.180 --> 00:36:29.840
So like uv pip install flask.

00:36:29.840 --> 00:36:33.300
And that doesn't call or use pip in any way.

00:36:33.300 --> 00:36:37.180
We're just using pip here to convey what the interface looks like.

00:36:37.180 --> 00:36:49.500
And part of the motivation there is at some point in the future, we probably want to add a new interface to uv that's a little bit more high level.

00:36:49.500 --> 00:36:55.380
So you could think of something like Poetry, where they have like Poetry install.

00:36:55.380 --> 00:37:00.200
You know, they have this sort of higher level interface for interfacing with packages.

00:37:00.200 --> 00:37:02.380
We want to do something like that.

00:37:03.060 --> 00:37:13.880
And so that's why we left the top level of the interface clear, because we might kind of like integrate and, sorry, innovate and like ship a bunch of stuff that would otherwise break this interface.

00:37:13.880 --> 00:37:23.780
So like, by putting this stuff under pip, we basically created this like isolated space where we can make sure that those commands like keep working no matter what we choose to change in the future.

00:37:25.000 --> 00:37:27.620
And it's very similar to the pip's interface, right?

00:37:27.620 --> 00:37:29.580
It's like pip install, then it could be a package name.

00:37:29.580 --> 00:37:31.960
It could be a requirement, -r requirements file.

00:37:31.960 --> 00:37:33.660
We support editable installs.

00:37:33.660 --> 00:37:38.760
We support like URL dependencies, get dependencies, all that kind of stuff.

00:37:38.760 --> 00:37:39.460
Right.

00:37:39.460 --> 00:37:44.060
All the stuff you might normally do pip install something for the most part, that's the same.

00:37:44.060 --> 00:37:44.520
Yep.

00:37:44.520 --> 00:37:45.160
Yeah, exactly.

00:37:45.500 --> 00:37:48.320
And we support a lot of the same flags, too, that like pip supports.

00:37:48.320 --> 00:37:54.700
So like --index URL, --extra index URL, like --no binary, like all that stuff.

00:37:54.700 --> 00:38:00.260
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.

00:38:00.260 --> 00:38:01.500
And we've added more over time.

00:38:01.680 --> 00:38:08.800
Like now we support like --no build isolation and stuff like that, that maybe most listeners have never even had to look at.

00:38:08.800 --> 00:38:11.700
But like, you know, these things matter in some circumstances.

00:38:11.700 --> 00:38:15.140
And so like over time, our goal is to add like more of the interface.

00:38:15.140 --> 00:38:22.500
But, you know, I would say for common use cases, I would expect that it just works.

00:38:22.500 --> 00:38:25.620
Like just adding uv at front, like it should just work.

00:38:25.620 --> 00:38:28.900
Now, as you become more complex, it won't.

00:38:29.180 --> 00:38:33.260
And you'll run into some, we have a whole document of like subtle ways that we deviate.

00:38:33.260 --> 00:38:34.800
Some are intentional.

00:38:34.800 --> 00:38:36.320
Some I consider bugs, right?

00:38:36.320 --> 00:38:37.780
Like some we want to fix over time.

00:38:37.780 --> 00:38:41.180
But the intention is that for most people, we want it to just work.

00:38:41.180 --> 00:38:44.460
Once we fix the first round of bugs following the release, of course.

00:38:44.460 --> 00:38:45.260
Yeah, yeah, sure.

00:38:45.260 --> 00:38:50.840
So you've got a uv venv VIMP, for creating a virtual environment.

00:38:50.840 --> 00:38:56.740
And it has a lot of the flags that Python dash MVNV would have, where you can say, you know,

00:38:57.080 --> 00:39:02.080
bring along pip or upgrade things or set the prompt name, that kind of stuff, right?

00:39:02.080 --> 00:39:03.160
Yeah, exactly.

00:39:03.160 --> 00:39:03.720
Yep.

00:39:03.720 --> 00:39:06.460
Similar for uv, pip, and then stuff.

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

00:39:11.820 --> 00:39:13.780
where people are like, what did you just do?

00:39:13.780 --> 00:39:15.560
These all have kind of aliases, right?

00:39:15.820 --> 00:39:21.180
Like uv, pip, install, dash, R, requirements.txt is just PIR, pip install requirements.

00:39:21.180 --> 00:39:22.480
You know, things like that, right?

00:39:22.480 --> 00:39:23.180
Yeah, yeah, yeah.

00:39:23.280 --> 00:39:25.940
And so try to just take the common stuff.

00:39:25.940 --> 00:39:33.780
And it doesn't matter if it's pip or uv really backing it from my CLI ergonomics, right?

00:39:33.780 --> 00:39:35.600
I'm just, I use my alias.

00:39:35.600 --> 00:39:38.400
And if I want to change that, I just go and edit it.

00:39:38.400 --> 00:39:43.360
And so for me, it was super easy to switch to adopt these things because I'm like, I edit

00:39:43.360 --> 00:39:49.920
my ZSH RC file once and now everything just, I just do the same stuff and it works, but

00:39:49.920 --> 00:39:50.880
the new way, way faster.

00:39:50.880 --> 00:39:51.440
Yeah.

00:39:51.440 --> 00:39:57.000
And, you know, the goal of like pip compatibility has been interesting because there are actually

00:39:57.000 --> 00:40:00.100
like some things that we very intentionally want to do differently.

00:40:00.100 --> 00:40:05.660
And like, I won't speak for the pip maintainers, but I think in some cases, there are probably

00:40:05.660 --> 00:40:08.160
things that they would do differently too, if they could.

00:40:08.160 --> 00:40:09.140
I think so too, yeah.

00:40:09.720 --> 00:40:16.080
Yeah, because like pip, I mean, pip is extremely important and its number one goal is like,

00:40:16.080 --> 00:40:19.200
it needs to be like robust, right?

00:40:19.200 --> 00:40:22.200
It needs to keep working and it needs to be compatible.

00:40:22.200 --> 00:40:27.660
And because it's like, it's truly like the cornerstone of like a lot of the Python ecosystem.

00:40:27.660 --> 00:40:32.500
And so pip, it's very, it's harder for them to change things, especially in a breaking

00:40:32.500 --> 00:40:32.800
way.

00:40:32.800 --> 00:40:36.400
And they have to be really thoughtful and do that over a long period of time.

00:40:36.600 --> 00:40:41.120
And so we're in kind of a privileged position, honestly, because we come in with a new tool.

00:40:41.120 --> 00:40:44.340
We can actually do a bunch of, choose to do things differently.

00:40:44.340 --> 00:40:48.920
And some people will get upset about it, obviously, because they're like, this isn't exactly how

00:40:48.920 --> 00:40:49.500
PIP does it.

00:40:49.500 --> 00:40:53.120
I'm trying to hold firm on some of those things and also be open-minded on others.

00:40:53.120 --> 00:40:53.420
Right.

00:40:53.420 --> 00:40:58.700
But like, you know, like one thing that we do that's different, that's, I guess maybe it's

00:40:58.700 --> 00:41:01.880
not evident from this exact, from this screen exactly, or I guess it sort of is.

00:41:01.880 --> 00:41:05.400
So when you do UVVM, we default to the name .vm.

00:41:05.400 --> 00:41:08.400
So like, if you don't provide a name, we just default to .vm.

00:41:08.400 --> 00:41:13.100
And there was a PEP to make that a standard that got pulled back.

00:41:13.100 --> 00:41:16.220
But like, it's not like we're trying to make it a standard, but I just think it's a good

00:41:16.220 --> 00:41:16.600
default.

00:41:16.600 --> 00:41:18.880
Like we want to abstract away some of this stuff.

00:41:18.880 --> 00:41:21.900
And so you can just like have a virtual, you can obviously pass a name if you want,

00:41:21.980 --> 00:41:23.060
but we default to .vm.

00:41:23.060 --> 00:41:24.400
That's different from other tools.

00:41:24.400 --> 00:41:29.740
And then, you know, the other thing is when you do UVPIP install, by default, we require

00:41:29.740 --> 00:41:30.620
a virtual environment.

00:41:30.620 --> 00:41:37.060
And so if you do UVPIP install Flask and there's no virtual environment, like we'll throw, we'll

00:41:37.060 --> 00:41:37.380
error.

00:41:37.380 --> 00:41:39.440
And it doesn't have to be active.

00:41:39.440 --> 00:41:42.660
We'll look for it in the current directory, even if it's not active.

00:41:42.660 --> 00:41:46.580
So like if you do UVVM, then UVPIP install Flask, like it will work.

00:41:46.580 --> 00:41:50.040
And in my opinion, it will do the intuitive thing, which is it will install into the environment

00:41:50.040 --> 00:41:51.160
in the current directory.

00:41:51.340 --> 00:41:53.000
So it's like, it's trying to provide...

00:41:53.000 --> 00:41:53.360
It will traverse up.

00:41:53.360 --> 00:41:58.080
Like if I'm a little farther down, it'll go up and say, oh, just, oh, that's amazing.

00:41:58.080 --> 00:41:58.440
Exactly.

00:41:58.440 --> 00:42:01.620
So it'll find the virtual environment in the current directory or any parent directory.

00:42:01.620 --> 00:42:10.240
So like for me, that's just like a nice default workflow that encourages virtual environments

00:42:10.240 --> 00:42:11.800
and like doesn't get in your way about it.

00:42:11.800 --> 00:42:15.940
And we do have a flag for installing outside virtual environments, but the difference is in

00:42:15.940 --> 00:42:20.640
UV, you have to opt in if you want to do something like install into the system Python.

00:42:20.700 --> 00:42:26.660
It's a very virtual environment first while abstracting away a lot of the details of virtual environments.

00:42:26.660 --> 00:42:30.380
So there are things like that where we've made intentional decisions.

00:42:30.380 --> 00:42:31.560
In my opinion.

00:42:31.560 --> 00:42:31.900
Yeah.

00:42:31.900 --> 00:42:32.580
Yeah.

00:42:32.580 --> 00:42:40.240
And I think, and it's nice because we can start with that behavior and we're in a privileged

00:42:40.240 --> 00:42:42.320
position because we can start with different defaults.

00:42:42.320 --> 00:42:43.320
Yeah, for sure.

00:42:43.320 --> 00:42:53.700
So if I do, excuse me, if I do a uv, VNV for a virtual environment, then maybe I uv pip install

00:42:53.700 --> 00:42:58.360
something, but then I forget and I pip install something else.

00:42:58.360 --> 00:42:59.200
Does it break?

00:42:59.200 --> 00:42:59.840
Is it okay?

00:42:59.840 --> 00:43:02.100
As in the third time there's no UV?

00:43:02.460 --> 00:43:03.160
Well, yeah, exactly.

00:43:03.160 --> 00:43:07.420
Like, so I'm in uv pip install, something uv pip install that.

00:43:07.420 --> 00:43:08.580
And I was, oh, I forgot this thing.

00:43:08.580 --> 00:43:09.420
It was pip install.

00:43:09.420 --> 00:43:11.140
Oh, I forgot the uv.

00:43:11.140 --> 00:43:11.960
To this day.

00:43:11.960 --> 00:43:13.000
No, it shouldn't.

00:43:13.000 --> 00:43:13.720
It shouldn't break.

00:43:13.720 --> 00:43:14.040
Assuming.

00:43:14.040 --> 00:43:16.120
So let's say you activate the virtual environment.

00:43:16.120 --> 00:43:16.660
Yeah.

00:43:16.660 --> 00:43:16.840
Yeah.

00:43:16.840 --> 00:43:17.400
It's already activated.

00:43:17.400 --> 00:43:17.920
Okay, cool.

00:43:18.000 --> 00:43:22.380
So you do uv VM, you activate the virtual environment, you do uv pip install flask, and then you

00:43:22.380 --> 00:43:24.440
do pip install black or whatever.

00:43:24.440 --> 00:43:24.980
Yeah.

00:43:24.980 --> 00:43:25.420
Something, yeah.

00:43:25.420 --> 00:43:30.880
That should work just fine because like the thing that we ultimately create in the virtual

00:43:30.880 --> 00:43:33.040
environment, like that's all based on standards.

00:43:33.040 --> 00:43:38.220
So like the stuff that we do in the virtual environment to install packages, it should look

00:43:38.220 --> 00:43:41.060
like roughly indistinguishable from what pip would do.

00:43:41.060 --> 00:43:42.940
And it's totally interoperable with pip.

00:43:43.300 --> 00:43:48.920
So like similarly, if you did pip install and then like pip install flask and then uv pip

00:43:48.920 --> 00:43:51.280
uninstall flask, like that would work correctly.

00:43:51.280 --> 00:43:55.680
Like pip would install flask and we would remove it because everything that pip and uv are doing

00:43:55.680 --> 00:43:58.100
in the virtual environment is based on standards.

00:43:58.100 --> 00:44:03.200
So the way that we add and remove packages, all that kind of stuff, it should be totally interoperable

00:44:03.200 --> 00:44:03.920
with other tools.

00:44:03.920 --> 00:44:04.860
Okay, cool.

00:44:04.860 --> 00:44:11.540
PyPI is pretty good at having analytics around what packages are being downloaded, what's popular,

00:44:11.540 --> 00:44:12.840
what platforms.

00:44:12.840 --> 00:44:18.100
Do you do anything like send a user agent or something so that people could answer the

00:44:18.100 --> 00:44:18.400
question?

00:44:18.400 --> 00:44:23.320
Or how many people are using straight pip and how many people are using uv in a year?

00:44:23.320 --> 00:44:29.000
Yeah, we sent, we set a uv user agent and it's right now it's just uv in the uv version.

00:44:29.000 --> 00:44:37.580
There's an open issue in the repo from Pradyan who works on pip that outlines all this stuff

00:44:37.580 --> 00:44:43.280
that pip includes in its own user agent, which we want to add, which is pretty interesting.

00:44:43.280 --> 00:44:44.120
I actually didn't know this.

00:44:44.120 --> 00:44:49.700
So pip in its user agent includes a lot of things about the current Python platform.

00:44:49.700 --> 00:44:55.640
Data that they use in PyPI basically to inform decisions.

00:44:56.260 --> 00:44:58.100
Like, oh, no one's using Python.

00:44:58.100 --> 00:44:58.100
Right.

00:44:58.100 --> 00:45:01.080
This is just, I don't think this is actually how it's used, but just as an example.

00:45:01.080 --> 00:45:03.680
Oh, no one's using Python 3.7 anymore.

00:45:03.680 --> 00:45:08.120
Let's lower priority on that because no one's installing Python with Python 3.7.

00:45:08.120 --> 00:45:11.360
And so we want to add, we don't have that right now.

00:45:11.360 --> 00:45:12.400
We're planning to add it.

00:45:13.740 --> 00:45:16.260
But yeah, it will be interesting to see.

00:45:16.260 --> 00:45:21.160
We can get statistics over time too on like uv and pip and how common they are in different

00:45:21.160 --> 00:45:21.560
dimensions.

00:45:21.560 --> 00:45:22.200
Yeah.

00:45:22.200 --> 00:45:26.880
You know, one thing that would be kind of fun to have is, I'm not sure if it's at all

00:45:26.880 --> 00:45:33.160
interesting to you, but to have some kind of cron job or background thing, even if you

00:45:33.160 --> 00:45:37.040
just interact with uv, if it kind of kicked off sort of a background process that did its

00:45:37.040 --> 00:45:43.040
thing, but, you know, take the history of maybe the top 500 packages plus the ones you've

00:45:43.040 --> 00:45:46.620
used and just kind of keep a cache up to date on your system.

00:45:46.620 --> 00:45:51.320
So if you're on an airplane or you're in a coffee shop or for some reason, the internet's

00:45:51.320 --> 00:45:51.900
not great.

00:45:51.900 --> 00:45:55.760
Like it's kind of pre-filled the cache and everything's there.

00:45:55.760 --> 00:45:55.960
Yeah.

00:45:55.960 --> 00:45:58.960
And that kind of, that might be fun.

00:45:58.960 --> 00:45:59.600
Yeah.

00:45:59.600 --> 00:46:05.280
We do have a dash track offline flag, which will like, it forbids network requests, obviously,

00:46:05.580 --> 00:46:09.740
but it, so like it'll, it'll try and do the full install without accessing the network.

00:46:09.740 --> 00:46:10.200
Yeah.

00:46:10.200 --> 00:46:10.500
That's cool.

00:46:10.500 --> 00:46:12.160
It would be cool to pre-fill the cache.

00:46:12.160 --> 00:46:12.740
Yeah.

00:46:12.740 --> 00:46:16.600
But it's just like, you know, if you're a uv user and you sit down on your computer and

00:46:16.600 --> 00:46:19.840
for some reason the internet's out, I'm at a conference, I'm doing a talk and it's got

00:46:19.840 --> 00:46:21.620
the dreaded, terrible conference wifi.

00:46:21.620 --> 00:46:22.820
It's not the end of your demo.

00:46:22.820 --> 00:46:24.260
It's just like, yeah, see how fast this is?

00:46:24.260 --> 00:46:24.760
It's amazing.

00:46:24.760 --> 00:46:25.580
Yeah.

00:46:25.580 --> 00:46:26.000
Yeah.

00:46:26.000 --> 00:46:26.120
Yeah.

00:46:26.120 --> 00:46:26.820
Yeah.

00:46:26.820 --> 00:46:30.860
It was actually, it's actually funny because like the benchmarking, like when we do benchmarks,

00:46:30.860 --> 00:46:36.560
benchmarks can just vary so dramatically based on like internet connectivity, right?

00:46:36.560 --> 00:46:38.500
Like that's often, that is often the bottle.

00:46:38.500 --> 00:46:43.120
I mean, it's not, it's clearly not always the bottleneck because we're able to be faster

00:46:43.120 --> 00:46:43.900
than other tools.

00:46:43.900 --> 00:46:48.560
So like if it was always the bottleneck, I don't think that wouldn't really be true, but, but,

00:46:48.560 --> 00:46:49.340
but it matters a lot.

00:46:49.340 --> 00:46:49.380
Yeah.

00:46:49.380 --> 00:46:54.040
And so sometimes I'll throw on, on macOS, they have a tool called network link conditioner.

00:46:54.040 --> 00:46:56.500
So you can actually force.

00:46:56.500 --> 00:46:57.900
Like drag your network down.

00:46:57.900 --> 00:46:58.580
Yeah.

00:46:58.580 --> 00:46:59.820
You can force it down.

00:46:59.820 --> 00:47:04.880
And the categories are like, it's not literally called like bad mobile phone or something,

00:47:04.880 --> 00:47:06.620
but it's, that's like basically what it is.

00:47:06.620 --> 00:47:06.760
Yeah.

00:47:06.760 --> 00:47:09.340
It's like, it's like, it's like very lossy edge network.

00:47:09.340 --> 00:47:11.180
Like those are like the pre-built category.

00:47:11.180 --> 00:47:14.960
It's pretty funny, but like it is actually, that's a very helpful thing for benchmarking.

00:47:14.960 --> 00:47:15.320
Yeah.

00:47:15.320 --> 00:47:18.740
And sometimes actually, if you have a really good network connection, sometimes it's actually helpful

00:47:18.740 --> 00:47:25.540
to, to set that anyway, to a pretty good level, because then at least it'll be like very consistent

00:47:25.540 --> 00:47:27.320
across your executions.

00:47:27.320 --> 00:47:28.760
Anyway, it's something I've learned over time.

00:47:28.760 --> 00:47:29.380
Yeah.

00:47:29.380 --> 00:47:31.380
That is super interesting.

00:47:31.380 --> 00:47:36.960
So one of the things I think it's interesting to consider here is obviously this is way faster.

00:47:36.960 --> 00:47:43.260
I saw some of the announcements and some of the discussion around the announcements and the

00:47:43.260 --> 00:47:45.140
people were really surprised how fast this is.

00:47:45.140 --> 00:47:48.380
And I think, I don't think Rust is the full answer.

00:47:48.540 --> 00:47:52.860
I mean, you tell me if I'm wrong, but like one part, obviously making the code run ultra

00:47:52.860 --> 00:47:55.020
fast, that is an important part of it.

00:47:55.020 --> 00:48:00.640
But it also seems like you all have rethought some of the internal algorithms and some of

00:48:00.640 --> 00:48:04.800
the caching and some of the ways things work, maybe with a fresh take on it, or you're not

00:48:04.800 --> 00:48:07.440
constrained by the way it's been done for many, many years.

00:48:07.600 --> 00:48:11.900
So what elements are at play to make it as fast as it is?

00:48:11.900 --> 00:48:13.700
Is it just Rust or is it something else?

00:48:13.700 --> 00:48:20.900
So Rust is important, but the way I typically talk about frame it is that Rust is kind of like an

00:48:20.900 --> 00:48:23.320
enabler to writing really fast programs.

00:48:23.780 --> 00:48:32.980
It forces you to slash lets you care about certain things that matter a lot for performance that like

00:48:32.980 --> 00:48:37.120
in Python, there's actually just no way to care about them.

00:48:37.120 --> 00:48:39.860
I'm talking specifically here about memory allocation.

00:48:39.860 --> 00:48:42.200
Like in Python, that all just kind of happens.

00:48:42.200 --> 00:48:45.940
In Rust, you're forced to think about, am I going to allocate memory here or not?

00:48:46.000 --> 00:48:48.920
And like, when is it going to be deallocated and all that kind of stuff?

00:48:48.920 --> 00:48:54.700
And so that unlocks the ability to care and like be really careful in how you manage it.

00:48:54.700 --> 00:48:58.800
And so Rust is like a really important, Rust is an important part of the success story here.

00:48:58.800 --> 00:49:05.240
But I think it's like really, I think it would be really like very incorrect to say that it's

00:49:05.240 --> 00:49:08.380
like all about Rust and it's not a Rust versus Python thing.

00:49:08.380 --> 00:49:09.000
Right.

00:49:09.000 --> 00:49:11.600
Like if we could just recompile pip with.

00:49:11.600 --> 00:49:13.500
Yeah.

00:49:13.500 --> 00:49:14.140
So if you took.

00:49:14.140 --> 00:49:14.640
If you took.

00:49:14.640 --> 00:49:15.540
Cython or something.

00:49:15.540 --> 00:49:15.860
Boom.

00:49:15.860 --> 00:49:16.800
It would just be.

00:49:16.800 --> 00:49:18.980
No, it wouldn't be as big of a deal.

00:49:18.980 --> 00:49:19.180
Right.

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

00:49:24.060 --> 00:49:28.200
it would probably be faster than pip, but it would not be nearly as fast as uv.

00:49:28.200 --> 00:49:30.820
Like we just do a lot of things differently.

00:49:30.820 --> 00:49:35.740
And part of like, I guess evidence for this too, is like throughout the development of uv,

00:49:35.740 --> 00:49:41.400
there were like multiple pull requests that sped up like uv as a whole by like 30 to 50%.

00:49:41.400 --> 00:49:42.480
So what does that say?

00:49:42.480 --> 00:49:45.540
That says that like, there's lots of different, those were all Rust programs.

00:49:45.540 --> 00:49:46.160
Right.

00:49:46.160 --> 00:49:51.280
So like we were able to write the same Rust program many times, optimizing it more and

00:49:51.280 --> 00:49:51.780
more and more.

00:49:51.780 --> 00:49:52.280
Right.

00:49:52.280 --> 00:49:52.620
Right.

00:49:52.620 --> 00:49:57.080
And so there's like so much engineering that went into making it fast.

00:49:57.080 --> 00:49:58.920
Some of it's like how the cache is designed.

00:49:58.920 --> 00:50:00.540
That was like a really important piece.

00:50:00.540 --> 00:50:03.680
And that's actually something that like pip could also do.

00:50:04.340 --> 00:50:10.420
And I think like it's possible a good outcome here actually is that like pip is able to take

00:50:10.420 --> 00:50:13.220
some of these changes and incorporate them over time.

00:50:13.220 --> 00:50:17.220
And we are kind of the guinea pig for that.

00:50:17.220 --> 00:50:21.660
Like we're going to kind of change user expectations a little bit about how the cache is set up.

00:50:21.660 --> 00:50:25.880
Like we're going to run into bugs about platform compatibility.

00:50:26.080 --> 00:50:28.960
Like we're going to run into bugs based on this cache design.

00:50:28.960 --> 00:50:29.200
Right.

00:50:29.200 --> 00:50:33.360
And like hopefully that could at some point help inform pip if they choose to redesign their

00:50:33.360 --> 00:50:34.020
cache this way.

00:50:34.020 --> 00:50:35.600
The cache design is really big thing.

00:50:35.600 --> 00:50:42.700
And then just a lot of like profiling the program, figuring out what the bottleneck is, and then

00:50:42.700 --> 00:50:47.140
like solving the bottleneck and just like really intense engineering work that was not me, but

00:50:47.140 --> 00:50:49.180
was like other people on the team to optimize some of that.

00:50:49.180 --> 00:50:55.260
Like a good example is it's like it sounds silly, but like we found that a bottleneck when

00:50:55.260 --> 00:50:57.580
all the data is cached and you're trying to do a resolution.

00:50:57.580 --> 00:50:59.020
So there's no network requests.

00:50:59.020 --> 00:51:00.140
Everything's local.

00:51:00.760 --> 00:51:06.760
One of the bottlenecks that we kept running into was parsing and comparing versions, version

00:51:06.760 --> 00:51:07.380
specifiers.

00:51:07.380 --> 00:51:13.580
So like in Python, when you have a requirements file, you have like FastAPI is greater than

00:51:13.580 --> 00:51:14.920
version one or whatever.

00:51:14.920 --> 00:51:19.780
And then in the FastAPI file, you have like FastAPI version 1.0.0, blah, blah, blah.

00:51:19.780 --> 00:51:24.660
So like those, like parsing those, and then we were comparing those.

00:51:24.660 --> 00:51:30.340
We were doing comparisons between version markers like so many times.

00:51:30.340 --> 00:51:32.740
Because it was just a constant thing in dependency resolution.

00:51:32.740 --> 00:51:34.080
It's like, can I use this dependency?

00:51:34.080 --> 00:51:35.520
Well, does it fit to this range?

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

00:51:44.460 --> 00:51:47.340
And it's like, it's like one of the most incredible pull requests I've ever seen.

00:51:47.340 --> 00:51:50.560
Like it's like so, like every, every commitment is like so interesting.

00:51:50.900 --> 00:51:55.560
And he like optimized it so massively that it was like, he's basically representing the version

00:51:55.560 --> 00:52:02.640
in the end by like, like a 64 bit, like a U64 integer and comparisons is just like compare

00:52:02.640 --> 00:52:03.280
the two integers.

00:52:03.280 --> 00:52:05.740
And like, there was just so much engineering that went into it.

00:52:05.800 --> 00:52:07.560
And it sped up the cache case by like 30%.

00:52:07.560 --> 00:52:12.260
And so there's a lot of, there's just a lot of engineering that went into it.

00:52:12.260 --> 00:52:17.900
And, you know, again, it's harder for pip to do some of those things because they, the code

00:52:17.900 --> 00:52:22.260
bases, they have a lot, they have, they have actual users to support, right?

00:52:22.260 --> 00:52:24.860
Like we were able to do this before we launched publicly.

00:52:24.860 --> 00:52:30.040
Like we could break things, like we can do things, you know, we can make massive changes

00:52:30.040 --> 00:52:31.660
to the code base in short periods of time.

00:52:31.660 --> 00:52:35.420
So, you know, we're in kind of a privileged position to be able to really optimize the

00:52:35.420 --> 00:52:36.300
performance like that.

00:52:36.300 --> 00:52:41.100
But, you know, it's a big part culturally of what we wanted to do too, is like, we're going

00:52:41.100 --> 00:52:42.260
to make this thing extremely fast.

00:52:42.260 --> 00:52:43.140
Yeah.

00:52:43.140 --> 00:52:49.160
I'm seeing also interesting secondary effects, you know, talks and not, not, I think that's

00:52:49.160 --> 00:52:51.800
talks, talking about using it, making it faster.

00:52:52.140 --> 00:52:57.600
Just now here, Henry says build 1.1 is faster from looking at uv and the next version will

00:52:57.600 --> 00:53:00.980
also add uv as an installer choice, which is pretty impressive.

00:53:00.980 --> 00:53:01.680
Yeah.

00:53:01.680 --> 00:53:05.940
That's been a really cool, that's actually something I didn't really anticipate, but I'm

00:53:05.940 --> 00:53:11.100
really glad has happened, which is that there's a little bit of like, we ended up building

00:53:11.100 --> 00:53:12.040
something pretty modular.

00:53:12.040 --> 00:53:17.740
And so there's been a little bit of a, or a lot of like integrations with uv that people

00:53:17.740 --> 00:53:18.340
have been building.

00:53:18.340 --> 00:53:23.800
Like, like, Bernard had the, had the talks uv thing that was out like within a week, I

00:53:23.800 --> 00:53:28.280
think, which was like use uv to power talks in different ways.

00:53:28.280 --> 00:53:28.720
Yeah.

00:53:28.720 --> 00:53:28.720
Yeah.

00:53:28.720 --> 00:53:32.520
Knox, I think supports it bill pipe a slash build.

00:53:32.520 --> 00:53:39.520
You know, I've talked, I've talked to the hatch maintainer, you know, like he's pretty interested

00:53:39.520 --> 00:53:43.420
in making uv like an optional backend for hatch.

00:53:43.420 --> 00:53:47.880
So like that's really cool to me because it's all just like magnifying the impact.

00:53:48.740 --> 00:53:49.240
Yeah.

00:53:49.240 --> 00:53:55.200
And again, I don't know how much of that I anticipated, but it's really cool to see that

00:53:55.200 --> 00:53:58.680
like you could plug it into these other tools and they can just like go much faster.

00:53:58.680 --> 00:53:58.680
Yeah.

00:53:58.680 --> 00:53:59.680
So I don't know.

00:53:59.680 --> 00:54:04.100
I mean, that's been like, that's actually been like a big highlight from the release, honestly,

00:54:04.100 --> 00:54:08.200
has been the reception from like other maintainers of other tools who have been excited to integrate

00:54:08.200 --> 00:54:09.480
it in different ways.

00:54:09.480 --> 00:54:11.700
Cause it's just not, it just didn't happen.

00:54:11.700 --> 00:54:15.260
Like rough wasn't nearly as much of a fit for that kind of thing.

00:54:15.260 --> 00:54:19.740
Like there just aren't as nearly, there are some, but it's just not as natural to have like

00:54:19.740 --> 00:54:21.360
integrations with rough in that way.

00:54:21.360 --> 00:54:24.480
But for uv, it makes a lot of sense and it's been really cool to see.

00:54:24.480 --> 00:54:24.880
Yeah.

00:54:24.880 --> 00:54:29.880
It's more, uv is more of a building block than rough is rough fits in editors and CI and

00:54:29.880 --> 00:54:30.300
stuff.

00:54:30.300 --> 00:54:31.020
Yeah.

00:54:31.020 --> 00:54:31.280
Okay.

00:54:31.280 --> 00:54:31.540
Yeah.

00:54:31.540 --> 00:54:36.180
And there were, there were other tools, but yeah, it was, it's, it's mostly an end user thing

00:54:36.180 --> 00:54:37.820
and not a library, I think.

00:54:37.940 --> 00:54:38.200
All right.

00:54:38.200 --> 00:54:38.660
All right.

00:54:38.660 --> 00:54:40.900
So a couple of interesting things out in the audience.

00:54:40.900 --> 00:54:42.380
Let's, let's knock them out.

00:54:42.380 --> 00:54:42.620
Okay.

00:54:42.620 --> 00:54:49.900
So Tushar asks, and this is, I think a big tension that's building in the Python packaging space

00:54:49.900 --> 00:54:53.900
is packaging tools use Python to do stuff.

00:54:53.900 --> 00:54:56.520
What are the packaging tools control the Python?

00:54:56.520 --> 00:54:59.200
Who, who is controlling whom here?

00:54:59.200 --> 00:55:02.680
And so Tushar asks, will uv also install Python sometime soon?

00:55:02.680 --> 00:55:06.720
Can I just express, Hey, I want to use 312 on this and these dependencies.

00:55:07.420 --> 00:55:07.920
Yeah.

00:55:07.920 --> 00:55:10.580
We almost, we almost certainly want to do this.

00:55:10.580 --> 00:55:13.440
I don't think it will be, it won't be required.

00:55:13.440 --> 00:55:19.460
Like you can still use your own Python, but we almost certainly want to add Python bootstrapping.

00:55:19.460 --> 00:55:25.600
So like, that's another reason why the dream workflow is like you use the standalone uv installer,

00:55:25.600 --> 00:55:29.680
because then it's like, it will actually install Python for you too.

00:55:29.680 --> 00:55:36.580
And so like the reason, so then it's like, you don't have to have Python on your machine basically to start being productive with uv.

00:55:36.580 --> 00:55:38.640
You can just bootstrap the environment for you.

00:55:38.640 --> 00:55:50.020
And we can also do, you know, yeah, it would just be nice if you did, you know, pip compile, like uv pip compile, --Python 3.13 or something.

00:55:50.020 --> 00:55:53.920
And then we just like bootstrapped Python 3.13 and did the resolution on your machine.

00:55:53.920 --> 00:55:56.220
Like that's, that's kind of the workflow that we're trying to build towards.

00:55:56.220 --> 00:55:56.760
Yeah.

00:55:56.760 --> 00:56:02.180
Since you're so uv centric as well, it could be uv, V and V, you know, dash that version.

00:56:02.180 --> 00:56:02.540
Yeah.

00:56:02.540 --> 00:56:03.040
A hundred percent.

00:56:03.460 --> 00:56:04.680
And then we bootstrap it.

00:56:04.680 --> 00:56:05.000
Yeah.

00:56:05.000 --> 00:56:07.380
If you don't have, if you've got a cache, you just give it.

00:56:07.380 --> 00:56:09.360
And if you don't, then you, you get it on the machine.

00:56:09.360 --> 00:56:09.760
Exactly.

00:56:09.760 --> 00:56:10.500
Yeah.

00:56:10.500 --> 00:56:11.100
Yeah.

00:56:11.100 --> 00:56:12.700
So we'll definitely, we'll definitely do this.

00:56:12.700 --> 00:56:17.560
again, I do think it's important that it's not like required to use like the uv pythons.

00:56:17.560 --> 00:56:17.900
Yeah.

00:56:17.900 --> 00:56:25.440
we actually kind of had to do like a minimal version of this for, for our CI and testing.

00:56:25.440 --> 00:56:28.820
so, but it was a bash script.

00:56:28.820 --> 00:56:32.040
And then I think it became a Python script, but eventually it would be like built into uv.

00:56:32.040 --> 00:56:32.580
Yeah.

00:56:32.580 --> 00:56:32.940
Yeah.

00:56:33.240 --> 00:56:33.440
Yeah.

00:56:33.440 --> 00:56:34.560
I think that would be really.

00:56:34.560 --> 00:56:35.020
Yeah.

00:56:35.020 --> 00:56:36.320
I think it'll be super, really quite awesome.

00:56:36.320 --> 00:56:36.860
Yeah.

00:56:36.860 --> 00:56:37.760
I think it will be too.

00:56:37.760 --> 00:56:39.380
let's see.

00:56:39.380 --> 00:56:43.000
Tushar also says loves that the --require V and V.

00:56:43.000 --> 00:56:43.580
Yep.

00:56:43.580 --> 00:56:44.340
As a thing.

00:56:44.340 --> 00:56:49.280
he thinks it'll become the default and also points out for those who don't uv that

00:56:49.280 --> 00:56:53.560
pip require virtual uv as an environment flag is in your RC files.

00:56:53.560 --> 00:56:54.220
It's pretty nice.

00:56:54.220 --> 00:56:55.100
I need to do that.

00:56:55.100 --> 00:56:55.200
Yes.

00:56:55.200 --> 00:56:55.840
The other day.

00:56:55.840 --> 00:56:56.040
Yeah.

00:56:56.040 --> 00:56:56.920
You can, you can.

00:56:56.920 --> 00:57:00.540
Oh, I spelled that to the, to my, to the wrong spot.

00:57:00.540 --> 00:57:00.560
Yeah.

00:57:00.560 --> 00:57:03.180
So pip can be configured to require virtual ones.

00:57:03.180 --> 00:57:03.780
Yes.

00:57:03.780 --> 00:57:04.180
Yeah.

00:57:04.180 --> 00:57:05.180
I do something weird.

00:57:05.180 --> 00:57:09.320
I'm actually looking at my terminal behind our, our shared screen meeting here.

00:57:09.700 --> 00:57:12.340
And my prompt says global V and V.

00:57:12.340 --> 00:57:16.560
And so one of the things that I do is I have a, just, if I log it, if I open up my terminal,

00:57:16.560 --> 00:57:18.340
it already has an activated virtual environment.

00:57:18.340 --> 00:57:19.640
That's just for whatever.

00:57:19.640 --> 00:57:20.580
Oh, interesting.

00:57:20.580 --> 00:57:22.620
Just to avoid messing up your system Python.

00:57:22.720 --> 00:57:23.960
Just to avoid messing up.

00:57:23.960 --> 00:57:27.880
Or so I can have a, I can just make that virtual environment version of Python.

00:57:27.880 --> 00:57:31.760
I want it to be, even if it's not the system one in general that I want to set, you know,

00:57:31.760 --> 00:57:33.060
just like it's its own thing.

00:57:33.060 --> 00:57:35.480
And so it wouldn't actually help me, but I still like that.

00:57:35.480 --> 00:57:36.260
Cause that's smart.

00:57:36.440 --> 00:57:37.440
Yeah.

00:57:37.440 --> 00:57:37.440
That's smart.

00:57:37.440 --> 00:57:38.440
Thanks.

00:57:38.440 --> 00:57:39.440
Yeah.

00:57:39.440 --> 00:57:41.860
I've learned a lot about like, oh my gosh.

00:57:41.860 --> 00:57:43.460
I mean, I've learned a lot about packaging.

00:57:43.460 --> 00:57:47.180
Like I didn't know like anything about packaging, you know, like six months ago.

00:57:47.180 --> 00:57:49.840
I shouldn't, I should actually shouldn't admit that.

00:57:49.840 --> 00:57:53.940
Cause it's really bad for my credibility, but like I've learned a lot about packaging.

00:57:53.940 --> 00:58:00.320
And in the past, like two weeks, I've also learned a lot about like system pythons, like

00:58:00.320 --> 00:58:06.700
how Python is installed and like how on like older versions of like Debian, like Python,

00:58:06.700 --> 00:58:10.820
they do like a lot of customization to Python that makes it like really different from like

00:58:10.820 --> 00:58:14.060
I learned like way more about this than I ever thought I would.

00:58:14.060 --> 00:58:16.060
I think it's fine to say that.

00:58:16.060 --> 00:58:18.560
I'm out on system pythons, but we do support them.

00:58:18.560 --> 00:58:19.080
Yeah.

00:58:19.080 --> 00:58:19.640
Awesome.

00:58:19.640 --> 00:58:24.040
You know, someone asked me like, no, Michael, you must know all of the standard library.

00:58:24.040 --> 00:58:25.080
I'm like, what are you crazy?

00:58:25.080 --> 00:58:25.600
No.

00:58:25.600 --> 00:58:26.140
Yeah.

00:58:26.140 --> 00:58:28.080
Why don't I want to stop the standard library?

00:58:28.080 --> 00:58:29.480
Yes, exactly.

00:58:29.480 --> 00:58:31.180
And I think it's the same thing about packaging.

00:58:31.180 --> 00:58:32.920
There's like so many edge cases.

00:58:32.920 --> 00:58:36.660
If you never interact with an edge case and you don't care about that edge case, why would

00:58:36.660 --> 00:58:38.680
you take the week or whatever to study it?

00:58:38.720 --> 00:58:40.960
Like it's just, it's irrelevant to you until you need it.

00:58:40.960 --> 00:58:44.560
And now you've dove in head first here.

00:58:44.560 --> 00:58:47.400
So then you're in the deep end.

00:58:47.400 --> 00:58:48.880
We spent so much time.

00:58:48.880 --> 00:58:51.400
I shouldn't even bring this up, but we did.

00:58:51.400 --> 00:58:51.720
Okay.

00:58:51.720 --> 00:58:52.840
When we were, whatever.

00:58:53.020 --> 00:58:56.980
I want to tell the whole story because I need to not, but like we did consider like lots

00:58:56.980 --> 00:59:01.940
of different names for this tool and multiple times we considered a name and then it turned

00:59:01.940 --> 00:59:05.000
out to be a standard library module that none of us had ever used.

00:59:05.000 --> 00:59:08.860
Like we wanted to use wave W-A-V-E.

00:59:08.860 --> 00:59:09.120
Okay.

00:59:09.300 --> 00:59:10.520
But that's a standard library module.

00:59:10.520 --> 00:59:10.880
Yeah.

00:59:10.880 --> 00:59:11.140
Yeah.

00:59:11.140 --> 00:59:12.100
I was like, oh, I had no idea.

00:59:12.100 --> 00:59:14.760
Is that for working with a wave audio files?

00:59:14.760 --> 00:59:15.360
Probably it is.

00:59:15.360 --> 00:59:15.560
Yeah.

00:59:15.560 --> 00:59:16.740
Like W-A-V files.

00:59:16.740 --> 00:59:17.020
Yeah.

00:59:17.020 --> 00:59:17.620
Yeah.

00:59:17.620 --> 00:59:18.160
Interesting.

00:59:18.160 --> 00:59:18.700
Yeah.

00:59:18.700 --> 00:59:19.400
There's a bunch of stuff.

00:59:19.400 --> 00:59:23.300
There's the whole dead batteries and removing certain things that like, you know, I know it's

00:59:23.300 --> 00:59:27.040
like a library, but some of these things I had never seen.

00:59:27.900 --> 00:59:28.200
Yeah.

00:59:28.200 --> 00:59:33.220
Well, it's naming tools and packages is its own whole special deal.

00:59:33.220 --> 00:59:35.900
And we have half a million packages in PyPI.

00:59:35.900 --> 00:59:38.200
And so how are you going to not conflict with that?

00:59:38.200 --> 00:59:42.060
Have an interesting name that's not for typo squatting.

00:59:42.060 --> 00:59:42.540
Yeah.

00:59:42.540 --> 00:59:42.940
Exactly.

00:59:42.940 --> 00:59:43.240
Hard.

00:59:43.240 --> 00:59:43.560
Yeah.

00:59:43.560 --> 00:59:44.200
It's a hard problem.

00:59:44.200 --> 00:59:44.380
Yeah.

00:59:44.380 --> 00:59:46.540
I don't even get me started on the name stuff.

00:59:46.540 --> 00:59:49.460
Someone actually donated this name to us, which is very kind of them.

00:59:49.460 --> 00:59:50.880
Oh, that's actually very cool.

00:59:50.880 --> 00:59:51.540
Very cool.

00:59:51.540 --> 00:59:51.980
All right.

00:59:51.980 --> 00:59:54.260
One other thing I do want to talk about here.

00:59:55.140 --> 01:00:01.200
Padnish says, asks about, you know, is there a future where Rye, R-Y-E and uv go hand

01:00:01.200 --> 01:00:01.700
in hand.

01:00:01.700 --> 01:00:02.780
Also great work.

01:00:02.780 --> 01:00:05.020
But maybe just talk a bit about Rye.

01:00:05.020 --> 01:00:06.560
That was by Armin Roeniger.

01:00:06.560 --> 01:00:10.460
And it kind of had a similar zen as uv, but really different.

01:00:10.460 --> 01:00:11.040
Yeah.

01:00:11.040 --> 01:00:12.860
So we, yeah.

01:00:12.860 --> 01:00:15.460
So we're taking over like maintainership of Rye.

01:00:15.460 --> 01:00:23.900
And we've just been like, I think I started talking to Armin like right after Rye got released,

01:00:23.900 --> 01:00:25.500
which was PyCon last year.

01:00:25.500 --> 01:00:27.240
I think it was during PyCon it got released.

01:00:27.240 --> 01:00:29.700
And we talked like shortly after.

01:00:29.700 --> 01:00:33.220
And we just found that like we were trying to do a lot of the, we were trying to solve a

01:00:33.220 --> 01:00:33.940
lot of the same problems.

01:00:33.940 --> 01:00:37.360
And we had like very similar vision for what we wanted packaging to be.

01:00:37.360 --> 01:00:40.160
But like we were coming at it from very different angles.

01:00:40.160 --> 01:00:44.140
Like Rye kind of came at it from, let's solve the Python bootstrapping problem.

01:00:44.340 --> 01:00:45.180
So we're going to ship a Rust tool.

01:00:45.180 --> 01:00:46.160
That seems like it's main focus.

01:00:46.160 --> 01:00:46.520
Yeah.

01:00:46.520 --> 01:00:47.200
Yeah, exactly.

01:00:47.200 --> 01:00:54.100
And then internally it was actually using like pip-tools and pip to do installs and resolutions.

01:00:54.100 --> 01:00:58.740
And then the thing that, I think the thing that Armin came to realize was like, if you want

01:00:58.740 --> 01:01:03.000
to fulfill this whole vision, you kind of need to like reinvent a lot of those internals.

01:01:03.000 --> 01:01:07.080
And meanwhile, like we were building uv, which was like basically those internals.

01:01:07.080 --> 01:01:12.860
And I was like, we're going to put a lot of effort into like building this packaging stack.

01:01:13.600 --> 01:01:17.080
And so we kind of found that like, it was just a really, we're trying to get to the same

01:01:17.080 --> 01:01:17.580
place.

01:01:17.580 --> 01:01:22.300
And we were putting in a lot of the engineering investment on building a lot of kind of building

01:01:22.300 --> 01:01:22.720
blocks.

01:01:22.720 --> 01:01:28.380
And we want uv to evolve into something that could like fully replace Rye.

01:01:28.380 --> 01:01:30.880
So we want it to evolve in that direction.

01:01:30.880 --> 01:01:36.140
And in the meantime, like we're going to keep maintaining Rye and kind of using it as like

01:01:36.140 --> 01:01:39.640
a little bit of a test bed for like experimental things.

01:01:39.640 --> 01:01:42.580
Like Armin added like pie test support to it, for example.

01:01:42.760 --> 01:01:45.700
So we're like, we're kind of playing with like, you know, that's meant to be more of

01:01:45.700 --> 01:01:49.220
an experimental test bed for like the future that we want to achieve.

01:01:49.220 --> 01:01:52.900
And over time, we're going to kind of evolve uv up to the point that hopefully it can fully

01:01:52.900 --> 01:01:53.440
replace it.

01:01:53.440 --> 01:01:55.900
And then we can provide a clear migration path for it.

01:01:55.900 --> 01:01:58.260
So we're going to keep maintaining it.

01:01:58.260 --> 01:02:03.280
It is our intention for uv to like, to, you know, supplant it at some point in the future.

01:02:03.280 --> 01:02:07.340
But it'll take us like time for it to get there and be able to do all the things.

01:02:07.340 --> 01:02:11.920
But, but the visions were just so similar that it seemed like it made a lot of sense to

01:02:11.920 --> 01:02:14.560
try and consolidate and kind of team up on it.

01:02:14.560 --> 01:02:14.980
Yeah.

01:02:14.980 --> 01:02:16.680
They do seem pretty similar.

01:02:16.680 --> 01:02:19.600
And I can, I can see the direction that you're going in it.

01:02:19.600 --> 01:02:20.920
It's going to make them more similar.

01:02:20.920 --> 01:02:21.560
Yeah.

01:02:21.560 --> 01:02:22.260
I know it'll take time.

01:02:22.260 --> 01:02:26.340
And like, you know, this release of uv is like, it really is like the first release,

01:02:26.340 --> 01:02:29.860
you know, it's like, like I kind of use some of this stuff as like pretty low level.

01:02:30.860 --> 01:02:34.540
Like, like we want to build something that feels higher level and more, more automatic

01:02:34.540 --> 01:02:35.260
in the future.

01:02:35.260 --> 01:02:40.000
But this, these are kind of like the ability to install and uninstall and resolve packages.

01:02:40.000 --> 01:02:44.500
These were like the fundamental things we needed and need for anything we were going to do.

01:02:44.500 --> 01:02:48.920
And so this goal was really, let's take those and let's put them in a form that's like immediately

01:02:48.920 --> 01:02:49.860
useful to people.

01:02:50.260 --> 01:02:50.940
Yeah, for sure.

01:02:50.940 --> 01:02:53.220
One more Rye question.

01:02:53.220 --> 01:02:54.240
Then I have other questions.

01:02:54.240 --> 01:02:56.260
So uv will replace Rye.

01:02:56.260 --> 01:03:01.600
Do you recommend using Rye or uv or what's the, what's that side of the story, right?

01:03:01.600 --> 01:03:01.900
Yeah.

01:03:01.900 --> 01:03:02.180
Yeah.

01:03:02.180 --> 01:03:02.460
Yeah.

01:03:02.460 --> 01:03:03.960
It kind of depends on what you're doing.

01:03:04.080 --> 01:03:06.580
So like, like Rye uses uv under the hood.

01:03:06.580 --> 01:03:11.060
So like Rye uses uv for resolution and installation.

01:03:11.060 --> 01:03:12.480
So if you're using Rye, you're using uv.

01:03:12.480 --> 01:03:19.980
I, like I say, I consider uv to be like, especially if you're like a company or something, like I

01:03:19.980 --> 01:03:22.680
would say uv is production ready for, for you.

01:03:22.680 --> 01:03:28.680
Rye, you're buying into a little bit more of something that's a little bit more experimental.

01:03:28.680 --> 01:03:33.300
Like I think Rye is a good fit for like professional projects, hobby projects, libraries, smaller

01:03:33.300 --> 01:03:33.740
projects.

01:03:33.740 --> 01:03:39.960
I don't know that I would like, you're just buying into more change, I think.

01:03:39.960 --> 01:03:40.420
Yeah.

01:03:40.420 --> 01:03:45.160
And so if you're already in a part of your monorepo, that's got a million lines of code

01:03:45.160 --> 01:03:46.380
and a hundred people on it.

01:03:46.380 --> 01:03:46.760
Yeah.

01:03:46.760 --> 01:03:49.460
You can certainly, you can certainly try it, but you should know that you're buying into

01:03:49.460 --> 01:03:51.280
something experimental is the way I'd put it.

01:03:51.280 --> 01:03:54.900
Whereas uv, like you could also view uv as experimental if you want.

01:03:54.900 --> 01:03:56.060
Like it's very new, right?

01:03:56.060 --> 01:03:59.980
Like we've, we're like when we launched, we had, I mean, I think having issues is actually

01:03:59.980 --> 01:04:02.800
good because it means people are using your project, but we had like hundreds of

01:04:02.800 --> 01:04:03.140
issues.

01:04:03.140 --> 01:04:07.440
And we closed and we closed, we've closed like hundreds and hundreds of issues since

01:04:07.440 --> 01:04:07.720
we launched.

01:04:07.720 --> 01:04:07.900
Yeah.

01:04:07.900 --> 01:04:09.840
You guys have been super, yeah.

01:04:09.840 --> 01:04:10.900
You've been super responsive on it.

01:04:10.900 --> 01:04:12.780
Like we, you and I've had some exchanges there.

01:04:12.780 --> 01:04:13.520
Yeah, we did.

01:04:13.520 --> 01:04:14.480
And yeah.

01:04:14.480 --> 01:04:14.760
Yeah.

01:04:14.760 --> 01:04:19.120
That's some nice changes I saw going on, but like I said, almost every day.

01:04:19.120 --> 01:04:19.960
It's getting like way better.

01:04:19.960 --> 01:04:20.660
It's great.

01:04:20.660 --> 01:04:20.940
Yeah.

01:04:20.940 --> 01:04:22.600
And it's just getting way, way better.

01:04:22.600 --> 01:04:26.820
Like that's the thing about developing in private is like, like we just, once we released

01:04:26.820 --> 01:04:30.260
it, we finally, we actually had users who could use it and tell us all the things we missed,

01:04:30.260 --> 01:04:31.540
also the things we didn't think about.

01:04:31.540 --> 01:04:32.940
It's just like every week getting way better.

01:04:32.940 --> 01:04:34.940
So like it's getting more and more stable.

01:04:34.940 --> 01:04:39.280
And like, I would use it in production for my stuff for sure.

01:04:39.280 --> 01:04:44.480
And I recommend it for production, but like Rye is just a little bit of a different story.

01:04:44.480 --> 01:04:48.460
I think with Rye, you know, it's not like we're going to shut it down tomorrow or anything

01:04:48.460 --> 01:04:48.880
like that.

01:04:48.880 --> 01:04:51.960
Like it's going to be, it's going to continue to be supported for sure.

01:04:51.960 --> 01:04:57.820
but you are, and I think it's branded this way, which is you are kind of buying into

01:04:57.820 --> 01:04:59.240
a little bit of an experimental tool.

01:04:59.240 --> 01:04:59.720
Yeah.

01:04:59.720 --> 01:05:00.960
Also a bit of a workflow.

01:05:00.960 --> 01:05:01.600
Yeah.

01:05:01.600 --> 01:05:02.980
It's a very opinionated workflow.

01:05:02.980 --> 01:05:03.480
Yeah.

01:05:03.480 --> 01:05:03.980
Yeah.

01:05:03.980 --> 01:05:07.460
Whereas UVs were designed to kind of slot into existing workflows.

01:05:07.460 --> 01:05:08.220
Sure.

01:05:08.220 --> 01:05:10.280
It's a little more foundational.

01:05:10.280 --> 01:05:15.880
Speaking of which, I really like that, you know, so many of these tools have their own,

01:05:15.880 --> 01:05:17.300
their complete own way.

01:05:17.300 --> 01:05:20.620
Like, I know you're going to do that, but we're going to start up our shell and then

01:05:20.620 --> 01:05:23.640
you're going to run these three commands and then we're going to have our own lock file

01:05:23.640 --> 01:05:24.800
and we're going to have our own things.

01:05:24.800 --> 01:05:30.000
And it's, it's amazing if you drink the Kool-Aid, if you go all in on the tool, but if you don't,

01:05:30.000 --> 01:05:33.020
then it's like, ah, okay, well, what is this thing even doing?

01:05:33.020 --> 01:05:35.260
It's more in my way than it's helping me, you know?

01:05:35.260 --> 01:05:35.700
And so on.

01:05:35.700 --> 01:05:42.580
So the fact that a lot of, a lot of this is kind of baking in the pip-tools way of there's

01:05:42.580 --> 01:05:46.800
going to be this external tool that can manage some of your stuff for you, but it's not

01:05:46.800 --> 01:05:48.040
prescribing a workflow.

01:05:48.040 --> 01:05:49.720
A hundred percent props for that.

01:05:49.720 --> 01:05:50.260
Love it.

01:05:50.260 --> 01:05:50.820
Thanks.

01:05:50.820 --> 01:05:51.640
Yeah.

01:05:51.640 --> 01:05:55.580
I wanted, like, I wanted to build something that, again, I use the word like modular a

01:05:55.580 --> 01:05:58.940
lot and I think it can mean different things, but like rough was kind of like this too.

01:05:58.940 --> 01:06:03.420
Like in rough, you can use it as like just a linter or like just a formatter or both.

01:06:04.360 --> 01:06:08.140
And like with uv, like you could use uv, like just to create virtual environments or just

01:06:08.140 --> 01:06:12.640
to do dependency resolution, but use pip for your installer or something.

01:06:12.640 --> 01:06:16.720
Like it's designed to be kind of flexible in how you choose to use it.

01:06:17.600 --> 01:06:19.960
And I want to, I want to maintain that.

01:06:19.960 --> 01:06:24.600
You know, I think, I think we'll start to introduce more opinionated workflows, but I think that

01:06:24.600 --> 01:06:29.620
we'll continue to provide this kind of pick and choose model as well.

01:06:29.980 --> 01:06:30.100
Yeah.

01:06:30.100 --> 01:06:30.540
Yeah.

01:06:30.540 --> 01:06:31.160
I think it's great.

01:06:31.160 --> 01:06:33.320
It lines right up with the way I do things.

01:06:33.320 --> 01:06:38.320
And also I really like it as both someone who might do presentations either at a conference

01:06:38.320 --> 01:06:43.620
or in a course or teaching because you're not putting, you know, the whole virtual environment

01:06:43.620 --> 01:06:48.380
stuff is already such a kind of a large barrier that comes a little early in people's learning

01:06:48.380 --> 01:06:49.500
path, right?

01:06:49.500 --> 01:06:50.660
They're like, I want to run Python.

01:06:50.660 --> 01:06:51.480
I want to run this thing.

01:06:51.480 --> 01:06:53.920
Whoa, you don't just install this.

01:06:53.920 --> 01:06:54.840
You don't just use it.

01:06:54.840 --> 01:06:56.620
We're going to talk about virtual environments.

01:06:56.620 --> 01:06:57.420
Like I don't care about those.

01:06:57.420 --> 01:06:58.080
I just want to run it.

01:06:58.080 --> 01:06:59.700
Like, but you're going to need to install something.

01:06:59.700 --> 01:07:00.460
So here we go.

01:07:00.460 --> 01:07:04.480
We're adding more workflow and more specific ways of working there.

01:07:04.480 --> 01:07:08.800
I think while trying to help a lot of times they end up just adding more friction at the

01:07:08.800 --> 01:07:09.120
start.

01:07:09.120 --> 01:07:09.600
Yeah.

01:07:09.600 --> 01:07:10.200
Yeah.

01:07:10.200 --> 01:07:16.280
And like, I guess my philosophy there is like, I want us to, I want us to like embrace virtual

01:07:16.280 --> 01:07:16.940
environments.

01:07:16.940 --> 01:07:20.940
Actually, Rai has this philosophy too, which is like Rai does use virtual environments and

01:07:20.940 --> 01:07:24.480
like virtual environments actually have a lot of, there's a lot of benefits to embracing

01:07:24.480 --> 01:07:24.760
them.

01:07:24.760 --> 01:07:28.700
Like all the editors and such, they're all built around virtual, they all are all built around

01:07:28.700 --> 01:07:30.700
virtual environment detection and stuff like that.

01:07:31.540 --> 01:07:36.340
But I wanted to feel, I want to feel a little, honestly, like it has a really bad reputation,

01:07:36.340 --> 01:07:40.740
but I wanted to feel more like node modules, you know, where it's like, it just kind of

01:07:40.740 --> 01:07:43.540
works in your, it just kind of sits in your project and your project just does the right

01:07:43.540 --> 01:07:43.820
thing.

01:07:43.820 --> 01:07:47.880
and I know people make fun of node modules usually for being big.

01:07:47.880 --> 01:07:51.780
but like, but that's the developer experience I want, which is you don't think, you don't

01:07:51.780 --> 01:07:53.440
think of the virtual environment as this weird other thing.

01:07:53.440 --> 01:07:56.120
It's just kind of like the project environment and it just kind of works.

01:07:56.120 --> 01:08:01.880
And I think, I think you've got that by not like fielding people from it, but abstracting

01:08:01.880 --> 01:08:04.060
some of it away for people that don't need to think about it.

01:08:04.060 --> 01:08:04.520
Yeah.

01:08:04.520 --> 01:08:10.400
There was a, there was an amazing, it's not a joke, but it's, I guess something that's

01:08:10.400 --> 01:08:14.320
a prank that somebody, came up with here.

01:08:14.320 --> 01:08:15.100
I'll put it on the screen.

01:08:15.100 --> 01:08:20.500
It's called when everything becomes too much, the npm package chaos of 2024.

01:08:20.500 --> 01:08:26.280
And I was just, as you were talking about node modules, it's amazing.

01:08:26.280 --> 01:08:33.380
So it's more of a statement of like, well, how super interdependent or how many combinatorial

01:08:33.380 --> 01:08:37.240
or transitive dependencies does a couple of npm things have?

01:08:37.240 --> 01:08:43.160
Like, for example, I used tailwind, but there was maybe 50 things in my, my node module for

01:08:43.160 --> 01:08:45.240
just using tailwind in my project.

01:08:45.240 --> 01:08:45.500
Right.

01:08:45.500 --> 01:08:51.460
So anyway, this one is some, this, an npm username, Patrick JS launched a troll campaign

01:08:51.460 --> 01:08:55.580
where a package called everything, it depended on every other npm package.

01:08:55.580 --> 01:09:01.060
So if you, you know, npm install everything that literally tried to download the repository.

01:09:01.060 --> 01:09:02.800
That's kind of, that's kind of amazing.

01:09:02.800 --> 01:09:03.600
Wow.

01:09:03.600 --> 01:09:09.160
I know it's, it's devious, but it's also kind of like, okay, that's, that's something else.

01:09:09.160 --> 01:09:09.940
Yeah.

01:09:09.940 --> 01:09:13.080
And Python independency trees tend to be much,

01:09:13.080 --> 01:09:17.500
like shorter, I guess, and like smaller, like you would tend to have way fewer dependencies.

01:09:17.500 --> 01:09:18.300
Yeah.

01:09:18.300 --> 01:09:21.220
they are sometimes like heavier, I guess.

01:09:21.220 --> 01:09:23.640
Cause like in Python, it's very common to have lots of native code.

01:09:23.640 --> 01:09:30.300
and like, I don't know, like PyTorch, like the PyTorch wheels that you download when

01:09:30.300 --> 01:09:33.840
they're zipped are like between a hundred and 200 megabytes.

01:09:34.380 --> 01:09:34.760
Wow.

01:09:34.760 --> 01:09:35.320
Okay.

01:09:35.320 --> 01:09:35.980
Yeah.

01:09:35.980 --> 01:09:36.180
Yeah.

01:09:36.180 --> 01:09:40.220
Like all the, all the ML stuff and all the native stuff, like those are like big, but,

01:09:40.220 --> 01:09:42.900
but the dependent, but the number of dependencies tends to be a lot smaller.

01:09:42.900 --> 01:09:43.500
Yeah.

01:09:43.500 --> 01:09:44.320
I totally agree.

01:09:44.320 --> 01:09:49.240
It's also very common to ship like foundational packages with like no dependencies or very few

01:09:49.240 --> 01:09:51.940
dependencies, which is very hard to do in, in JavaScript.

01:09:52.300 --> 01:09:53.060
Yeah, it is.

01:09:53.060 --> 01:09:55.020
it definitely is.

01:09:55.020 --> 01:09:55.400
All right.

01:09:55.400 --> 01:09:56.780
I think we're getting short on time here.

01:09:56.780 --> 01:10:01.200
I think I probably should let you go back and knock out another release of uv.

01:10:01.200 --> 01:10:02.340
I do have to do a release today.

01:10:02.340 --> 01:10:02.660
Okay.

01:10:02.660 --> 01:10:03.120
Thank you.

01:10:03.120 --> 01:10:03.380
Awesome.

01:10:03.380 --> 01:10:04.020
Cool.

01:10:04.020 --> 01:10:08.500
So Tony, the audience has been using uv in production for a couple of weeks now.

01:10:08.500 --> 01:10:09.100
Awesome.

01:10:09.100 --> 01:10:10.320
Seems very excited about it.

01:10:10.320 --> 01:10:12.000
And also I have two.

01:10:12.000 --> 01:10:14.180
It's an absolute delight.

01:10:14.180 --> 01:10:14.880
It hasn't.

01:10:14.880 --> 01:10:15.800
Oh, thank you so much.

01:10:16.300 --> 01:10:16.540
Yeah.

01:10:16.540 --> 01:10:21.800
I know there's certain things that it didn't do like right away, but then it, it came

01:10:21.800 --> 01:10:23.480
out and you added them quickly.

01:10:23.480 --> 01:10:28.640
I know there was some criticism for y'all for developing this in private and then releasing

01:10:28.640 --> 01:10:28.880
it.

01:10:28.880 --> 01:10:31.300
And I just want to say like, you know, thanks for doing that.

01:10:31.300 --> 01:10:32.460
And what's the alternative?

01:10:32.460 --> 01:10:37.300
You start with just a blank GitHub repo and people start to say, well, you should do this.

01:10:37.300 --> 01:10:37.920
You should be doing that.

01:10:37.920 --> 01:10:38.760
Like we have a vision.

01:10:38.760 --> 01:10:42.580
Let us just like get it a little structure in place and then we'll open source it.

01:10:42.580 --> 01:10:44.200
Like give us a month, you know?

01:10:44.200 --> 01:10:45.320
Yeah.

01:10:45.320 --> 01:10:45.700
I don't know.

01:10:45.700 --> 01:10:47.960
I think it's, I think it's excellent work you're doing.

01:10:47.960 --> 01:10:49.200
I appreciate it.

01:10:49.200 --> 01:10:49.880
I appreciate it.

01:10:49.880 --> 01:10:50.040
Yeah.

01:10:50.040 --> 01:10:50.500
Yeah.

01:10:50.500 --> 01:10:50.800
Yeah.

01:10:50.800 --> 01:10:52.460
You know, like I said at the start, it was different.

01:10:52.460 --> 01:10:58.220
It's different this time because anything we release, like, you know, you could work

01:10:58.220 --> 01:11:01.660
on a rough for a month and nobody cares until it starts to catch some traction.

01:11:01.660 --> 01:11:01.900
Right.

01:11:01.900 --> 01:11:03.560
But this is the instant that it hits.

01:11:03.560 --> 01:11:04.240
Yeah.

01:11:04.240 --> 01:11:07.420
We knew people would at least, would at least look at it and at least try it.

01:11:07.420 --> 01:11:10.980
And I think, you know, we wanted to make sure that whatever we released, first of all

01:11:10.980 --> 01:11:11.400
was good.

01:11:11.400 --> 01:11:13.500
And second of all, that we were ready to maintain it.

01:11:13.980 --> 01:11:18.280
And then I think with packaging too, it's like, there's just a lot of, it's just such

01:11:18.280 --> 01:11:22.980
a complex space that like, I wanted to make sure that we had a lot of clarity in the messaging

01:11:22.980 --> 01:11:27.280
around what the tool is and what it's not and like what we want it to be and what it isn't

01:11:27.280 --> 01:11:27.580
yet.

01:11:28.040 --> 01:11:32.600
And so I'm really happy with how the launch went and I've really appreciated just all

01:11:32.600 --> 01:11:37.620
the excitement, activity, engagement that we've had on the repo.

01:11:37.620 --> 01:11:39.180
It's been like, I don't know.

01:11:39.180 --> 01:11:45.380
I mean, honestly, it's been a lot of work, but it's like really, really, no, but it's awesome.

01:11:45.380 --> 01:11:48.340
It's like so energizing for me and for the team.

01:11:48.340 --> 01:11:52.420
And to see all the people picking it up and making it the foundation of their projects.

01:11:52.420 --> 01:11:53.640
And yeah, it's really cool.

01:11:53.640 --> 01:11:53.920
Yeah.

01:11:53.920 --> 01:11:54.880
And it's cool.

01:11:54.880 --> 01:11:57.680
You know, I guess another, like one other thing that's a little different this time is

01:11:57.680 --> 01:12:02.700
like, I talk, I just talked to more people who work on Python tooling at companies now than

01:12:02.700 --> 01:12:07.120
I did when I released Ruff, just because over the course of the past year, I've just met

01:12:07.120 --> 01:12:10.080
a lot of people and we've just talked about how they're using Ruff, how they're not.

01:12:10.080 --> 01:12:13.920
And so just hearing some of those stories too, of how like companies are starting to use

01:12:13.920 --> 01:12:17.340
it and like what the blockers are and like how much of a speed of it's providing has been

01:12:17.340 --> 01:12:18.200
pretty cool to see too.

01:12:18.540 --> 01:12:20.440
So yeah, I appreciate, I appreciate it though.

01:12:20.440 --> 01:12:21.520
Yeah, you're welcome.

01:12:21.520 --> 01:12:21.800
All right.

01:12:21.800 --> 01:12:23.280
We'll leave with this final thought from Juan.

01:12:23.280 --> 01:12:25.620
I installed 94 libraries in around two seconds.

01:12:25.620 --> 01:12:26.200
Incredible.

01:12:26.200 --> 01:12:26.540
That's great.

01:12:26.540 --> 01:12:26.780
All right.

01:12:26.780 --> 01:12:27.160
Yeah.

01:12:27.160 --> 01:12:29.240
All right.

01:12:29.240 --> 01:12:33.000
Well, I'm excited to see where things go and, you know, we'll maybe do a follow-up when,

01:12:33.000 --> 01:12:36.880
when you've got some more, more of the ideas in place.

01:12:36.880 --> 01:12:37.600
Sounds great.

01:12:37.600 --> 01:12:38.840
No, it's always, it's always a pleasure.

01:12:38.840 --> 01:12:39.860
Thanks so much for having me on.

01:12:39.860 --> 01:12:40.560
I really appreciate it.

01:12:40.560 --> 01:12:41.020
Yeah.

01:12:41.020 --> 01:12:41.540
Thanks, Charlie.

01:12:41.540 --> 01:12:45.240
This has been another episode of Talk Python To Me.

01:12:45.240 --> 01:12:47.060
Thank you to our sponsors.

01:12:47.420 --> 01:12:48.660
Be sure to check out what they're offering.

01:12:48.660 --> 01:12:50.080
It really helps support the show.

01:12:50.080 --> 01:12:56.400
It's time to stop asking relational databases to do more than they were made for and simplify

01:12:56.400 --> 01:12:58.640
complex data models with graphs.

01:12:58.640 --> 01:13:05.080
Check out the sample FastAPI project and see what Neo4j, a native graph database, can do

01:13:05.080 --> 01:13:05.460
for you.

01:13:05.460 --> 01:13:09.900
Find out more at talkpython.fm/neo4j.

01:13:09.900 --> 01:13:11.880
Want to level up your Python?

01:13:12.280 --> 01:13:15.920
We have one of the largest catalogs of Python video courses over at Talk Python.

01:13:15.920 --> 01:13:21.100
Our content ranges from true beginners to deeply advanced topics like memory and async.

01:13:21.100 --> 01:13:23.760
And best of all, there's not a subscription in sight.

01:13:23.760 --> 01:13:26.680
Check it out for yourself at training.talkpython.fm.

01:13:26.680 --> 01:13:28.780
Be sure to subscribe to the show.

01:13:28.780 --> 01:13:31.560
Open your favorite podcast app and search for Python.

01:13:31.560 --> 01:13:32.860
We should be right at the top.

01:13:33.260 --> 01:13:38.040
You can also find the iTunes feed at /itunes, the Google Play feed at /play,

01:13:38.040 --> 01:13:42.240
and the direct RSS feed at /rss on talkpython.fm.

01:13:42.640 --> 01:13:45.200
We're live streaming most of our recordings these days.

01:13:45.200 --> 01:13:49.320
If you want to be part of the show and have your comments featured on the air, be sure to

01:13:49.320 --> 01:13:53.040
subscribe to our YouTube channel at talkpython.fm/youtube.

01:13:53.040 --> 01:13:55.080
This is your host, Michael Kennedy.

01:13:55.080 --> 01:13:56.380
Thanks so much for listening.

01:13:56.380 --> 01:13:57.540
I really appreciate it.

01:13:57.540 --> 01:13:59.440
Now get out there and write some Python code.

01:13:59.440 --> 01:14:20.320
I'll see you next time.