You have a larger growing Python code base? If you struggle to run builds, tests, linting,
and other quality checks regularly or quickly, you'll want to hear what Benji Weinberger has
to say. He's here to introduce Pants Build to us. Pants is a fast, scalable, user-friendly build
system for code bases of all sizes. It's currently focused on Python, Go, Java, Scala, Kotlin,
Shell, and Docker with more languages to come. So you can see on that project that even has
multiple languages at play. This is Talk Python to Me, episode 388, recorded October 6th, 2022.
Welcome to Talk Python to Me, a weekly podcast on Python. This is your host, Michael Kennedy.
Follow me on Twitter where I'm @mkennedy and keep up with the show and listen to past
episodes at talkpython.fm and follow the show on Twitter via at Talk Python. We've started
streaming most of our episodes live on YouTube. Subscribe to our YouTube channel over at talkpython.fm
slash YouTube to get notified about upcoming shows and be part of that episode.
This episode is brought to you by the Local Maximum Podcast over at localmaxradio.com
and Microsoft for Startups, Founders Hub. Get support for your startup at talkpython.fm
slash founders hub. Transcripts for this and all of our episodes are brought to you by Assembly AI.
Do you need a great automatic speech to text API? Get human level accuracy in just a few lines of code.
Visit talkpython.fm/assembly AI. Benji, welcome to Talk Python to Me.
Thank you. It's great to be here.
It's great to have you here. I'm quite excited to talk about pants and build and bringing a little bit more structure and automation to the developer workflow using this tool that you all built.
Very happy to talk about that. Something I've been very passionate about for a long time.
Yeah, you've been working on this quite a long time, as we will see. But before we get into all the details there, let's start with your story.
How do you get into programming and Python?
I love this question because I've been a software developer for 25 years or so. So I've been around for a while.
You and me both, almost the same duration there.
So, you know, we've seen some stuff. But I first got into computers when I was about 10 years old.
And my uncle, who is a big gadget nut, bought a very, very early home computer. This was in the UK. So it was the Sinclair ZX80, if anyone's familiar with that.
1K of RAM, you know, 8-bit machine. It was, I had just never seen anything like it. And I was instantly smitten by it and got really into it then.
And at some point, got my own home computer and at some point realized, oh, this is sort of a thing I want to do for the rest of my life.
Now, granted, at that time, I also thought I would play with Legos for the rest of my life.
So it's not like I'm always right about that. But in this case, I absolutely was.
It's pretty awesome that we get to do that, right?
You know, it's like, oh, this is such a neat little project. And I would just do this for fun.
But if people pay me, I get to build even more ambitious things.
And a lot of times those are just the thoughts and dreams of kids who don't know better, right?
Just wait till you get in the real world. But as programmers, that's not true. Like we get to do it all the time.
It's absolutely unbelievable that your childhood hobby can become your grown up profession if you have the right hobby.
Yeah, exactly. It's important to pick good hobbies, kids.
If you're out there listening and you haven't picked a hobby yet and you're not there, yeah, pick a good hobby.
Yeah.
You talked about the 1K of RAM and the retro thing. I just started working on this project last night.
No, two days ago using CircuitPython. And for, what is that thing? $17, I got an ESP32 feather.
Whoa.
Little microchip. It has a Wi-Fi built in. It's got like a temperature sensor and all these things.
And all you need to make it go is just plug in a USB-C. That thing is like a 240 megahertz.
Two megs of RAM, four megs of storage, which is not much at all. But like it fits like it has two thirds of your hand.
And it's unimaginably powerful compared to what the types of computers you're talking about, right?
Oh, that, as I said, 1K of RAM. It had the Zilog Z80 was the processor, which I believe was clocked at about four megahertz or something.
It was, yeah. I mean, and at the time, you know, when you're a child, a million sounds like a lot.
So I'm sort of, what do you mean megahertz? Like I can't count to a million.
Yeah, that's unbelievable. That's right. And here we are, well, well past the early Pentiums for $14 or $17.
Anyway, it's just, it's really interesting to think about the different types of computers that we have to work with and where we all start.
The other thing that I always find interesting is thinking back to early 90s, late 80s, those computers and their interfaces were so basic.
And yet the possibility that at least I experienced when I worked with them, it seemed so great and so amazing that even stuff today doesn't come close to where you're like, I see where this is going.
It's going to be incredible.
There's definitely a joy. I mean, when you use the word basic, I'm assuming in lowercase, but the interface to many of them was literally the language basic all uppercase.
Or you could just write machine code directly. And those were your only two options essentially.
And so you were either, you know, 10 print your name, 20 go to 10, or you were messing around with registers.
And once you learned how to do that, it was such a joy.
You're essentially, you're melding with the hardware in some way.
And it's, yeah, today, obviously, mostly for good, we are 19 layers removed from the hardware.
And if you're going to be removed from the hardware, Python's a good way to do it.
But yeah, definitely some joy has been lost and replaced with other joys.
It's a new kind of joy.
Now I pip install something in three lines.
I have like a cluster of servers at my command.
It's a different kind of joy than working with registers.
All right, well, let's get into the main topic.
Let's talk about pants, this project that you all have created.
Its role, as we started, stated briefly at the beginning, is really about helping orchestrate common tasks that we have to do to build and run and prepare software.
And it's only getting more and more complex.
I guess Python grows up, as you sort of put it, as we were chatting before I hit record.
As Python grows up, as it's being used on larger projects, as it's being used across larger teams, the expectations of what it means to have a piece of software and run it is changing and evolving, right?
So maybe we could just start by talking about some of the pain points of large software, scaling software, Python in particular.
Sure. An important piece of background here that I'm sure all the listeners will be familiar with is what has happened to Python in the last 10 to 15 years.
I mean, I started programming in Python about 20 years ago on Python 2.2.
It was sort of fancy bash at that point, right?
It was just the language, the little bit of glue you used around the edges of your real code, which was written in C or whatever.
And fast forward to today, and if you look at the process of particularly over the last 10 years, Python is this absolutely critical language that has grown up incredibly and is now being used to build large systems.
It's being used as the language of choice for data science.
It's being used as the language of choice for DevOps.
It is absolutely crucial language that large, growing, scalable code bases are increasingly being built out of.
And that's presumably everyone listening is a fan of Python as I am.
And so there are good reasons why this is the case.
But we're still a little behind the curve on the tooling that you need to grow a Python code base.
The standalone Python tooling, and there are so many great tools in that toolkit, they're pretty single use.
And they tend to be designed to assume that you have a small, single use, sort of standalone binary that's the only thing that your code base contains.
But now increasingly, you have these large, growing code bases, sometimes referred to as monorepos, where you have a lot of Python code, possibly code in other languages as well.
You're trying to share code across a bunch of different projects and a bunch of different binaries.
You have a lot of, you may be deploying out of a single code base.
You want to deploy many microservices.
You want to deploy AWS Lambdas.
You want to deploy many different Docker images.
You have this complexity that you need to manage.
And so with other languages, there have been tools around to help you deal with this problem.
Python and for more contemporary languages, many of the solutions tend to come standard with that language's tool chain, such as, you know, Go just comes with a Swiss Army knife and Rust comes with a Swiss Army knife.
Python does not, for better or worse, come with a Swiss Army knife.
It comes with, you know, there are many, many blades out there.
And particularly in its focus on Python is designed to help you grow and scale that Python code base so that all of the steps you need to take to go from authoring some code to having it be validated, tested, checked, you know, have passed all its quality control checks and be ready to be deployed or used in production.
Rather than you manually having to figure out, well, which tools do I need to invoke in which order?
How do I need to ensure that they are consistent?
How do I do the least amount of work in the least amount of time that is necessary to assure those quality checks?
That is all a very automatable problem.
And that's essentially what Pants is.
It can look at your code base.
It can look at changes to your code base and say, oh, you want to run tests?
Here's the actual work that needs to happen.
And here are the tools that need to be invoked.
Sure.
So maybe you want to run pytest.
And as we'll learn, Pants has some great ways to speed up things like executing tests.
Some of that's parallelism.
Some of that's going, you know what?
We already did that work.
Nothing's changed.
Carry on.
Exactly.
Pants is essentially the layer between either you as a developer working on your laptop or
your CI environment and the underlying tools of which, you know, there are so many.
And Pants, I think, supports well over 20 Python tools.
And it's fairly easy to add more.
So, for example, test being a very important example.
You can say, hey, Pants, test, you know, run all the tests on everything that is affected
by my current set of changes.
The system can look at your code, look at the dependencies, perform all this analysis and
say, well, that means I actually need to invoke pytest on these underlying tests.
And if that means I need to first install pytest in a hermetic environment, I will do that.
Pants also runs everything in these hermetic sandboxes, which means they are neither consume
nor create side effects, which means all of this work can be cached at a very fine-grained
level.
You can cache the result of an individual test, apply concurrency at the level of an individual
test.
And so if you have eight cores on your machine, you can run eight tests at the same time and
you only need to run the ones that have not, whose inputs have changed because everything
else is cached potentially.
Yeah.
So that's the test example.
Then you could look at another really important quality control check is linting and formatting.
There are, I don't know, eight or 10 different linters and formatters for Python and Pants can
orchestrate them all in the right order.
It understands the distinction between linters, which don't modify your source code so they can
all run concurrently, and formatters which do modify your code so they have to run sequentially.
So it's a lot of, it's this layer between you that allows you to not worry about which tools
do I need?
How do I install them?
How do I isolate them?
How do I cache their results?
How do I reason about concurrency and what can and can't be run together?
It just takes that away from you.
One of the most powerful things for me personally, when I see all of this, how it brings all of
these things together is a lot of times, well, yeah, I should probably run the linter on that,
but it's fine.
Maybe I should run the tests, but I didn't change that much.
I mean, it was only a couple of lines of code.
I don't really, you know, like there's these different steps you got to keep in mind.
And at each level, you're like, do I need to do this?
Or do I need to remember to do it?
Or is it justified to disrupt what I'm thinking about?
And if it's just, you know, pants build or pants tests, and you don't have to worry about it,
and the system just does it all for you, you, at least personally, I am more willing to adopt
more software engineering practices and guards on my code.
If it doesn't feel like I have to do them, you know what I mean?
If I don't actually have to remember like, well, I was doing five steps and that was a lot.
Now I'm doing six and I'm really sick of these steps now, you know, if it's the same number
of steps and it's fast enough because of the caching and parallelism, then why not adopt it?
Exactly.
And I think an underappreciated complication is when it's not an individual adopting it,
but a team.
So a team wants to assume some best practices, but now everyone on your, you want to adopt a new
linter or a new quality control check of any kind, that's more cognitive load on behalf of,
you know, now what do you do?
Do you send an email to everyone on the team saying, well, now you have to run this as well.
You can set up your existing build layer pants in this case to add, apply that new linter.
And it just happens.
Nobody has to change their workflow.
What, where we want to get to is essentially, and we're in many cases, very close to this
is you run a single command on, as a developer, you run that same single command in CI and the
right thing just magically happens.
And the ability to do the right thing magically depends on the ability to do dependency analysis,
to build a fine grain workflow, to apply concurrency and caching to it.
And as I think we'll, we'll get to maybe later, even not just concurrency and caching on your
machine, but remote execution in a cluster and shared remote caching so that work is being
shared.
Not just, you know, it's not just past work that you have done, but past work that anyone
individually or in CI has done.
Yeah, that's fantastic.
And if you've got a large code base, that starts to pay off.
Yeah.
I want to talk to you about monorepos, but before we get to there, maybe you could just
give a quick shout out about some of the language support.
I mean, obviously we're talking about Python tools for Python code bases for Python developers
and data scientists, but we might also live in multilingual heterogeneous environments at
work and on our projects.
And we might have, you know, some Kotlin for a mobile app and our Python for APIs or
something like that.
So yes, Pants is not a Python only tool, but it is a Python first or a Python centric tool
in that when we, there is a long history to the project, but the current iteration of Pants,
which we very unimaginatively called Pants V2, because we're not great at naming, it launched
almost exactly two years ago, two years ago at the end of the month.
And with just support for just Python.
And since then we've added support for Go, for Java, for Scala, for Kotlin, for Shell.
The next thing we're looking at very closely, obviously, is JavaScript and TypeScript.
Can't ignore those.
But one of the things that makes Pants stand out and, you know, the P in the name is no
accident is the recognition that Python is not, is no longer this third cousin that you sort
of put at the end of the list of languages to deal with.
And it's sort of an afterthought.
But really this thing is designed for Java.
It was really part of the big driving use cases.
But if you have many languages in your repo, or if you have no Python at all in your repo,
Pants is still a useful tool for you.
Because you still get the benefit of all the analysis that it does on your behalf.
Indeed.
And people will see that Python, Pants is written sort of top layer in Python and lower
layer in Rust and the extensibility layers in Python.
So there's a lot of Python first, as you say there.
But I did want to call out, it does work on these other languages.
So if you're trying to adopt some kind of automation that involves multiple languages, this might
work for you.
Yep.
And we are always interested in people who have opinions about what the next languages
we support should be.
Obviously, as I said, JavaScript, TypeScript, very high on the list.
I suspect Rust is very high on the list, partly because we use it and partly because it is a
very up and coming and for very good reasons.
This portion of Talk Python to Me is brought to you by the Local Maximum Podcast.
It's an interesting and technical podcast that dives into trends in technology, stats, and more.
But rather than tell you about it, let's hear from Max and Aaron about their show.
We are now on with Talk Python to Me.
Let's say hi to all the Python fans.
Hi, Python fans.
I'm Max Sklar.
I have actually done a lot with Python myself.
So I am a fan of Talk Python.
Do you know Python, Aaron?
I took a course years ago, but I am a little rusty.
We are here today to talk about our podcast, The Local Maximum.
We've been on a roll lately with a new episode every week, and I wanted to share with you what
we've been up to.
Here on The Local Maximum, we tackle subjects in software and technology, topics as diverse
as the philosophy of probability to Elon Musk's next move.
For Talk Python listeners, I want to highlight a couple of recent episodes of The Local Maximum.
In 248, for example, I found out about an open source library that maps the world into
hexagons.
And some pentagons.
I had a discussion with an author about games and puzzles and another on a novel approach
to doing the job search well.
We discussed the ramifications of AI-generated art.
Have we reached peak creativity, or is this just another Local Maximum?
All developer tools kind of come of age when they can make themselves.
They're now fully independent where a language or a tool builds its own self with its own
features.
So yeah, if you could do that for Rust, then it can kind of be a part of that group.
Yep.
Self-hosting is a major milestone in any sort of build type project.
Indeed.
All right.
Quick question from the audience.
Mustafa out there says, how does Pants handle bulk publishing of packages where I might have
a set of preconditions to auto-publish it?
Intervals of all package that meet those conditions or something along those lines.
Great question.
So Pants, as I should mention, there are many different types of deployable that it can build.
I mentioned like AWS Lambda or Google Cloud Functions, or we have a format that's specifically
of interest to Python users called PEX, which stands for Python Executable.
And it's basically a single file that contains your Python code and all of its transitive dependencies.
So it is ready to run as long as there's an Python interpreter on the system you run it on.
And it even knows how to find that interpreter.
Interesting.
PEX came from you guys.
Yes.
Oh, I had no idea.
I mean, I've heard of PEX, but I didn't associate it with Pants.
That's cool.
Yeah.
I mean, other systems can also build PEX, and PEX has a standalone command line tool that
you can use to build PEXs.
But Pants is the home base of PEX.
But I think the question was about building and publishing Python distributions, for example,
to PyPI, which Pants can obviously do.
And I'm not 100% sure I'm answering the question appropriately.
But I think one of the ways that Pants can help you here is it knows when code has changed.
So if you're publishing a large number of packages from your repo, it can do the math of, you know,
here are the, by tracking dependencies, it can do the math to say, based on the changes,
since the last time this thing was published, it now has changed and needs to be republished.
So it can give you a lot of that logic.
When it comes to auto-publishing at intervals, I guess I would say Pants can tell you whether
it meets the conditions based on dependency analysis, etc.
There is no auto-publishing per se.
Pants is a tool you have to invoke.
So you could cron around it or something like that.
Yeah.
Cool.
You mentioned monorepos.
Now, you also mentioned sharing code.
If I've got, say, some SQL model definitions that point at what my database looks like, well,
my API code probably needs access to the right version of those.
But so do my data scientists for their library that talks using SQL model to get the data into their notebooks.
And if those things get out of sync, as we know, SQLAlchemy will go bonkers and say,
you're missing a column here.
Done.
Crash, right?
And so keeping that stuff in sync across these different projects can be challenging.
Is that the idea behind these monorepos?
Yes.
That's one of the reasons why they are increasing in popularity.
So the problem is, as your codebase grows, when your codebase is small, there are no problems.
And as your codebase grows, you're faced with kind of two, you're faced with a decision on how to manage that.
One is to keep breaking it up into multiple smaller repos, essentially, each one with their own build and their own practices.
And the way you consume code across them is through publishing, through version publishing.
Maybe you make your SQL models a data package and you publish it to an internal PyPI and everyone consumes it and they pin their
versions just like...
Exactly.
So the problem with that is that there are several problems with it, but a big one is that you're inviting the famous dependency hell problem,
which is already bad enough with third-party requirements, into your first-party code.
So the problem is, when you make changes to a library, you have no way of knowing who is consuming you upstream from you and therefore what changes they might need.
Now, you might say, well, not my problem because everything is supposed to be versioned,
but that breaks as soon as anyone needs to upgrade anything because now they have this horrific upgrade problem that is happening potentially weeks or months after the changes that are breaking them have happened.
So you're kind of pushing the problem off.
Where a monorepo is helpful is that you get this visibility into all of the upstream dependencies.
Essentially, if all the tests in the monorepo pass, you know that your changes have not broken your coworkers.
You know that you can use in-repo tools like GitGrep to find or any kind of discovery tools and dependency analysis that tools like Pat's offer within the repo to find out the impact of your changes.
And this is why monorepos are increasingly popular.
And, you know, it's not to say that because a bunch of other companies are doing it, you should be doing it.
But it is instructive to note that Google and Facebook and Twitter and a lot of successful companies have gone in that direction or in Google's case started out in that direction.
Right.
It has to be said that with monorepos or without, you need appropriate tooling.
So at some point you have to pick your poison.
But the reason I am biased towards monorepos, having worked at companies that have had one unified code base and companies that have had a very fragmented code base, is that the structure of your code base tends to recapitulate the cohesion and structure of your organization itself.
And if everybody is collaborating on a single large repo within reason, you don't necessarily need to have literally one repo for the entire company, but a small number of large repos with boundaries between them that makes sense because they don't mutually depend on each other, let's say.
Then that mutuality and that sharing of code creates more cohesion at the organizational level.
And when you have a very fragmented code base, you tend to have a fragmented organization.
Now your organization resembles, you know, a loose collection of warring tribes more than a single unified organization.
So I am biased towards monorepos.
And while you can use pants very effectively in even, you know, multiple smaller repos, I do think it supports the monorepo architecture really well.
And the last thing I would say about this is just to really clarify, because we get a lot of questions about this.
Monorepo is about your repo architecture, nothing to do with your deployment architecture.
So it is not the opposite of microservices.
For example, if you have many microservices, you probably want them to be in a single repo because they share, as you said, data models, they share code.
And it is actually easier to deploy many microservices out of a single repo than constantly creating new teeny repos and having to go through the whole publish and consume dance every time you want to publish a microservice.
And so publishing many microservices out of a single monolithic repo is actually a common pattern and a very effective one, in my opinion.
Yeah, I guess if you have a monolith where the code is architectured into one giant thing, it necessarily means that you're probably just going to have it in one repo.
But if it's microservices, there may be this temptation to have, well, we've got 10 microservices.
So we've got 20 repos because here's each one for the service and then the shared bits got to be broken out into their own so they can be reused.
Yes.
Just essentially, you get a much, in a monorepo, you get a much tighter development loop because you are cutting out all of the publishing.
Everything is consuming.
All the inner code-based consumption is happening at head.
So you don't have this constant publishing and consuming.
Yeah.
Yeah, I hadn't really thought about it that way.
But a lot of the tools, the really good tools that we have, things like PyCharm and stuff, we can open them up and go to a function or a variable or a class and right-click and say, show me all the uses of this.
But if there's a bunch of different consumers of your library, well, you don't really know because anybody could be grabbing something and using it.
But if it's a monorepo and it says no usage is found, well, that means more.
Exactly.
The consumption metadata on published artifacts goes the wrong way, right?
It says, the metadata that gets published with the wheel says, here is what this wheel consumes, but it has no idea who consumes it.
And so if you want to figure that out, now you need a whole bunch of tooling.
So why not just cut that out entirely?
Yeah, and you get things like refactor, rename, or to cross the whole company sort of in interesting ways as well.
Okay, cool.
Maybe we should touch a little bit on the history of pants.
There's, I know pants 1.0 has been around for a long time, and then there's this 2.0 version.
You want to tell people a bit about the changes there?
They maybe have experienced it a while ago.
Sure thing.
So pants, what we now refer to as pants v1, was a project that started as an internal project at Twitter,
and it was focused primarily on Scala and how can we speed up Scala builds and make them more organized and more tractable.
It then got open sourced out of Twitter and was used at a handful of other Scala-using companies, notably Foursquare.
Square used it as well.
There were a few companies of that vintage of early 2010s, Silicon Valley startups that were using Scala in a big way.
So, in fact, v1 is basically gone at this point.
I think there's a handful of organizations still maybe using it.
We're desperately trying to get them onto v2.
The pants v2 is a thing that we launched two years ago.
There's a complete ground-up re-implementation.
It really only shares a name with the old one and sort of project home with the old one.
The code is entirely new.
As you alluded to earlier, one of the big differences in the implementation is that the execution engine in v2 is written in Rust,
and the APIs are async Python 3.
But that is an important difference.
But the bigger difference is the design itself is very different in that the v2 system learned a lot from our experience with v1,
both in terms of the implementation and how to make important features like caching and concurrency just fall out of the design
rather than be this laborious thing you have to add at every corner.
And also, an equally important lesson was, unlike many other systems, including PANS v1,
which came out of a single company and were really tailored for that company's use cases,
with v2, we wanted to build something that was for everyone,
that any organization, large or small, could use and get.
You shouldn't have to work at Microsoft or Google or Twitter to get this quality of build experience.
Anyone should be able to.
And that required looking at the use cases of a lot of organizations of different languages and different sizes.
And one thing we learned was nobody wants to write a ton of build metadata.
If anyone's used a system like PANS v1 or Bazel or Buck or something similar,
you start by potentially refactoring your code base to be what the system expects.
And then you write thousands and thousands of lines of what so-called build files.
We wanted to eliminate all of that.
And so the system is designed to accept your code base as it is.
And it doesn't require huge amounts of build metadata.
It requires small amounts that it can mostly generate.
But the important information, which is the dependencies,
it actually infers at runtime by looking at import statements and various other tricks and heuristics
for figuring out what your code's actual dependencies are.
So that saves a huge amount of time and makes it a lot easier to use and a lot easier to adopt.
So that's kind of why v2 came about.
We wanted to build something that wasn't like,
here's something we built for Twitter, throw it over the wall and you can use it if you want to.
But here's a thing that was designed for you, designed for Python, designed to be easy to adopt,
designed to be easy to use, designed to be easy to extend,
has a robust API that is async Python 3 essentially.
And that's where that project came from.
Yeah, it's really interesting how it came from kind of this big tech side of things.
But second take, it's like, well, how do we just make this for all the projects, not just the large ones?
There's that, there was an interesting article and it's, you know, quoted in various forms a lot.
Like, you're not Facebook, you're not Google, you're not LinkedIn.
Speaking to most people, right?
I mean, there are people who actually are there, but like for most people who look at these architectures
and what's happening, they may, oh, look how they're scaling this.
And like, yeah, but you just have a hundred users.
You don't need to like go to that much architecture and crazy designs for, you know, what you're doing.
And so it's, I can see how it would be a temptation to have like an overly complicated system that comes along.
But it looks to me like this is really easy to adopt.
It is significantly easier and we are constantly working on automating the adoption.
There is a, one of the commands in Pants is, this is the only Pants related pun we've allowed ourselves in the system is called tailor because it quote unquote tailors your metadata.
It essentially generates, it does inspection of your code and generates a bunch of metadata, not including dependencies.
Those, as I mentioned, are inferred at runtime, but this is kind of a thing you run periodically because this is metadata that you may want to manually tweak.
And so we're constantly working on making that easier and easier to adopt for real world cases.
So just one obvious example is many repos have dependency tangles and circular dependencies and Pants v2 can handle that.
Those other systems cannot, including Pants v1.
And those other systems were not really designed for easy adoption because they didn't need to be, because they were only designed to be adopted once by a captive audience of all the developers at that company.
We want this to be adopted thousands of times by thousands of organizations.
So we want it to be much, much easier.
This portion of Talk Python to Me is brought to you by Microsoft for Startups Founders Hub.
Starting a business is hard.
By some estimates, over 90% of startups will go out of business in just their first year.
With that in mind, Microsoft for Startups set out to understand what startups need to be successful and to create a digital platform to help them overcome those challenges.
Microsoft for Startups Founders Hub was born.
Founders Hub provides all founders at any stage with free resources to solve their startup challenges.
The platform provides technology benefits, access to expert guidance and skilled resources, mentorship and networking connections, and much more.
Unlike others in the industry, Microsoft for Startups Founders Hub doesn't require startups to be investor-backed or third-party validated to participate.
Founders Hub is truly open to all.
So what do you get if you join them?
You speed up your development with free access to GitHub and Microsoft Cloud computing resources and the ability to unlock more credits over time.
To help your startup innovate, Founders Hub is partnering with innovative companies like OpenAI, a global leader in AI research and development, to provide exclusive benefits and discounts.
Through Microsoft for Startups Founders Hub, becoming a founder is no longer about who you know.
You'll have access to their mentorship network, giving you a pool of hundreds of mentors across a range of disciplines and areas like idea validation, fundraising, management and coaching, sales and marketing, as well as specific technical stress points.
You'll be able to book a one-on-one meeting with the mentors, many of whom are former founders themselves.
Make your idea a reality today with the critical support you'll get from Founders Hub.
To join the program, just visit talkpython.fm/founders hub, all one word, no links in your show notes.
Thank you to Microsoft for supporting the show.
You talked about some of the tools that you could use.
Maybe we could go through that list of common tools real quickly and you could just give us your thoughts on why you think it's great and maybe why you might want to adopt it and make it part of your flow.
Because with Pants, you don't have to add more steps, as we said.
So some of the tools you've called out are mypy.
I know you're a fan of Python 3 and Pype annotations.
Tell people quick about mypy.
So for those who aren't familiar, mypy brings a level of rigor to your Python quality control that is fantastic.
Essentially, you add type annotations to your Python 3 code and mypy performs static type checking and is absolutely tremendous.
You know, it is essentially a sort of compilation step for Python.
Right.
It's not actually generating code, but it is performing type checks that finds a wide variety of bugs and issues.
And I would never go back to non-type checked Python.
Interesting.
Yeah.
So it's like, if I were to compile it, what would happen?
We're not actually going to, but let's go through that and give you a report, like sort of print out the warnings and errors that you would have seen in a compiled language.
And then we'll carry on.
You know, a common way these things are referred to in Python is type hints, which kind of implies they have no effect.
But with mypy, it's a little bit closer, right?
Right.
So they have no runtime effect, it is true, but they have the type annotations.
Well, they can if you, in certain circumstances, pants itself uses its own code type annotations at runtime in an interesting way.
But generally, running mypy just is an extremely effective quality control check in your code.
But getting set up with mypy can be complicated.
And with pants, you just pants check all my code or pants check all my code that has changed since my last, you know, since my last edits.
And it will install mypy and it will set it up and it will run it.
First time you do that, you'll get many, many errors, I'm sure.
I'm sure.
I'm sure you will.
Another one you've given a shout out to is Protobuf for protocol buffers.
I don't know that I've spoken very much about those at all on the show.
I mean, people know REST and JSON.
They may have scars from SOAP and XML.
I'm not sure how many people are doing it.
It depends on how long they've been doing this kind of stuff.
But what's Protobuf?
I just had XML PTSD for a second there.
Yeah, I'm sorry.
I'll send a therapist your way after the show.
So Protobuf is a really fabulous tool out of Google that generates code in many languages from a .proto file,
which is a language neutral interface definition language.
And that works well with gRPC, which is the Google RPC language,
where it actually generates RPC code and stubs so that you can use protocol buffers.
These over-the-wire protocols is referred to as protocol buffers.
And you can just use them as this binary interchange format that is very efficient over the wire.
So exchanging binary data, if you say, here's four bytes, that's the account.
And then here's the length of the string is the next four bytes.
And then doing that manually is super tricky.
And so protocol buffers is a formalization of that.
And then this tool would maybe write the Python code that understands a particular exchange.
Okay.
So PaaS knows how to do code generation in general.
It supports many code generators, including Thrift, which is a sort of similar in spirit to Protobuf.
But Protobuf is a very prominent one.
And the idea is that it will generate this Python code out of, you have this very succinct interface definition,
and it generates fairly elaborate Python code that can serialize and deserialize these messages
and send them via RPC interfaces and send and receive them via RPC interfaces over the wire,
where the thing on the other side of that RPC interface might not be Python at all.
But they're all talking the same IDL.
And yeah, protos are very efficient binary formats.
So they use things like variable length integer encoding.
So the same message will be significantly more compact in Protobuf as it will be in JSON.
That said, in probably many, many cases, JSON is absolutely fine, right?
Exactly. There's a ton of value to be like, I can point my web browser or postman or something at that and see the answer.
Yes.
Right? Like, that goes a long ways.
But if you're exchanging really low latency, lots of data as fast as you can, then, you know, JSON is probably not it.
Certainly XML with namespaces and XSLT is definitely not the right thing.
So this sounds like a cool, more modern way to do it.
Some other tools. We've already talked about pytest. People know what pytest is.
Black formatting, right? Auto formatting a code.
So is that much?
Stop the indentation arguments.
Yes.
Oh my God.
When we adopted black in the pants repo, everybody, myself included, got upset for about 10 minutes and then realized that far more important than which format is that there is format that is enforced automatically.
I personally used to at least prefer two space indents to four space indents. Black is the reason it's called black.
For those who don't know, is that famous, you can have any color you want as long as it's black.
I think that was Henry Ford.
I think so. Model T.
So basically, it's a very opinionated formatter that just says this is what Python code should look like.
And you know what? I embrace robot overlords in this case.
Yeah.
It's absolutely wonderful. I can just do pants format and it just formats all the code.
That is the, there are no more arguments. Like the true formatting is whatever black outputs.
And pants, again, makes it very easy to adopt black.
It also makes it easy, I should mention, for linters, for formatters, even for mypy, pants has affordances in it to help you adopt them incrementally, which you kind of have to do.
If you have an existing code base, you may want to adopt, you know, it takes time to, so black is very aggressive, but there are many other linters that pants can run.
And a doc formatter and flake eight and pilot and bandit and so on.
And I sort, and you may want to adopt them incrementally and pants has ways to help you do that.
And certainly with mypy, because it relies on upstream.
mypy, you kind of have to adopt independency order because it relies on upstream type annotations.
And so there are ways to do that.
Right. To get the most out of it, you've got to have the, we call these three functions.
Well, those three functions have to have type information and be valid.
And I got to start at the foundation with those.
Bandit's interesting.
I don't know how many people run Bandit.
Probably people who accept user input probably should or input from the internet.
Tell people about Bandit.
I'm not super familiar.
I'm no expert on Bandit, but it's just about security checks.
So it will automatically find common security issues in your code.
And again, Pants makes it very easy to adopt it.
You essentially just enable the Bandit plugin.
Pants, I should imagine, has this plugin architecture where you can opt in to whichever sort of bits of functionality you want.
So you enable the Bandit plugin.
And that's kind of it.
And the next time you run Lint, it will run the Bandit checks.
And it will yell at you about all the security issues that's found in your code.
That's cool.
So you have these different categories.
Like you have a test category, a Lint category, and so on.
And then in your configuration, you can say, when I say Lint, I mean these three things.
Correct.
So what you refer to as a category in the sort of Pants jargon is referred to as a goal.
So it's basically what you type on the command line.
You type Pants test means run test.
Pants Lint means run all the Linters.
But what all the Linters means depends on your configuration.
Sure.
That makes a lot of sense.
Maybe one more.
I know the list is kind of unbounded in a sense.
But AWS Lambda or sort of functions, serverless functions in general.
There's probably other ones.
You could probably do Azure functions and other things as well.
The two we support at the moment are Google Cloud Functions and AWS Lambdas.
Yes.
So Pants knows how to take your Python code and package it into a Lambda function that you can
deploy to AWS or a Cloud Function you can deploy to GCP.
The management of that kind of stuff is super picky because you might have 20 functions coming
out of all these different pieces of code.
Did you forget to push that to that particular function point?
That's really hard to do to keep that straight.
If you're using serverless, if you're using Cloud Functions, you probably have many of them.
And a tool that can tell you which ones need to be redeployed based on changes, because it's
very simple with Pants to say which Cloud Functions have been affected by any transitive change since
this tag, since this deployment tag.
And it will tell you, it'll just give you a list and you can just repackage them and redeploy
them.
Without having to repackage and redeploy everything every single time.
Awesome.
Yeah, that sounds incredibly helpful if you're using them.
So the reason I wanted to go through that list here is like if adopting those tools and those
features sounds interesting, the more you adopt, the more the tools like Pants can help lower
the burden and just make that automatic, right?
Exactly.
It generally just takes away the pain of how do I adopt this tool?
How do I run it?
How do I configure it?
How do I make sure that everyone in my team is on the same page about how to use these things?
It just automates away all of that.
It also supports things like you can run a Python REPL that contains all the dependencies of the bit of code you're interested in.
It can do, because it has this fine-grained dependency analysis, it can know that even if you have like a big requirements.txt file, it knows which sub parts of that requirements.txt and their transitive dependencies are relevant to every given binary.
So now you're not managing many different sets of requirements for each of your, let's say, Cloud Functions or each of your Docker images.
That's all happening automatically for you.
Nice.
Let's talk about running these tasks and caching, performance, parallelization, and so on.
So one thing it has here right on the pantsbuild.org page, and you've hinted at this a few times, is that it speaks Git.
And so it has this way of understanding changes.
Yes.
So built into it is the ability to say, like things like when you want to run tests, you can say run all the tests.
You can say run all the tests in this directory.
You can say run all the tests, run this specific test.
You can say run all the tests that have this tag, this like a tagging mechanism sort of where you can label things.
Or you can say run all the tests that are affected by changes since this other Git state.
So you can say, you know, as you're working on your laptop, you can say, all right, run the tests that could possibly be affected based on my changes since the main branch.
It will internally use Git tooling to figure out what that means.
So it'll say, OK, which files have you changed and which things are downstream from those changes.
When you say affected by, how is that determined?
Does that mean I saw there's some Python code that my, here's my test and my test is importing this and these import those?
Or does it do like code coverage?
What does it base its opinion on of what's changed?
It based its opinions on its view of your code's dependencies.
Now, almost all of that view comes from analysis of import statements.
Occasionally, you may have to override those.
So, for example, if you're using Django, we have good support for Django, but Django notoriously does a huge amount of dynamic loading based on strings in settings.py.
Right, right, right.
Occasionally, sometimes pants can actually look at those strings and figure it out.
It has a mode where you can tell it that if it sees strings in a file that look like module names to assume that those are like imports.
But sometimes that doesn't work.
And so you can manually override the dependency inference and you can say, actually, here's a dependency that's important and you failed to infer it.
Or the opposite, you can exclude a dependency that pants mistakenly inferred.
But that's extremely rare.
So it bases that on its automatic static analysis of your dependencies.
Cool.
So one of the things that might be important when you're running these steps is, for example, the protobuf thing.
Right.
Its step has an output and maybe that output is consumed by some other, maybe by the tests or maybe the tests load up the Python file that was generated by that to go talk to some binary blob and see if it understands it.
It's really important those run in order, right?
Yes.
So from your dependencies plus its understanding of which jobs need which inputs, needs to consume which inputs and which jobs produce those inputs as their outputs, it constructs this very fine-grained workflow graph.
And that is exactly where the caching and the concurrency comes from.
So every node in this graph, and it could be thousands even, every very fine-grained node in this workflow graph knows exactly which inputs it needs.
And the work is done in the right sequence.
So if you have two pieces of work that neither of which depend on each other, right, in the DAG sense, they are independent, they can run concurrently, and they will.
So presumably, if you have multiple cores on your machine, they literally will run, they could run in parallel at the same time.
But obviously, if a little work unit needs the output of some other work unit to be its input, then it will wait for those.
And how all that is strung together is using all of the work as described.
As I mentioned, the API for this is Python 3, is async Python 3.
And so you have these things called rules, which are these async coroutines.
And the Rust engine strings together executions of these rules based on data dependencies.
And the data dependencies use type annotations, use just regular Python 3 type annotations, to say, to describe the types of the inputs and outputs.
And so the engine can say, ah, you, this rule needs to consume an output of this type.
I have found a rule that produces an output of that type based on some other input that I already have.
So I will string them together.
And it will do that recursively until it ends up at sort of the initial data, which obviously it has.
Right.
We'll start here, go down this path in that order.
Some of them, though, can be parallel, right?
Like Bandit and PyFlake.
Those just, mypy, all those just look at the code and say, looks good or doesn't look good.
And here's your warning message, right?
And so you can, does it by default or just optionally parallelize that?
No, it will happen by default.
It will always, I mean, you can control the amount of concurrency.
Let's say you're running multiple things on the machine and you don't want it to consume all your cores.
You can tune that down.
But just normally by default, it will use as much concurrency as the graph allows.
So every one of those small work units is candid for being executed concurrently with other ones.
But it is also, and this is really important, a candidate for being cached.
So many, many intermediate steps can be cached.
In a typical iterative run when you're iterating on your laptop and you're developing and you make some changes and you run some tests and you make some changes and you run the tests again.
So much work that normally would be repeated will not be repeated by pants because it will be, the outputs will be pulled from cache.
Yeah, that's fantastic.
Because every one of those nodes has its, it runs, as I said, with no side effects.
It runs in a sandbox with no side effects and its inputs and outputs are statically defined.
So it can be correctly cached every time.
So you don't, you as an author of a plugin, for example, don't have to think about caching or concurrency.
You just write to the API and caching or concurrency fall out of the design.
That's really neat.
And I can imagine on a large code basis, things like Bandit and mypy, all those analysis tools, they can take a while.
And if you just change one file, and especially if you're in the monorepo business, where it's not just for your website, but there's a ton of stuff, you don't want to rerun all those things.
So it could really get a lot faster.
You can get a lot of speed increases that way.
Yes.
Yeah.
One of the hesitations to adopt tools like this is it keeps rerunning from scratch over and over, and that makes it slow.
The other one is while you may run it, your teammates may have a less buy-in on some of these linting, formatting, testing ideas.
And if you just do that in CI, well, when you check it in, it works.
Someone else gets their code.
You merge theirs.
You check it in again.
And it breaks the build.
And it can be super frustrating.
Is there a way, like a pre-commit hook or some other mechanism to encourage these to be run by everyone?
You certainly can have a-
Or is that a personnel problem?
That really depends on the organization.
We tend to see adoption of pants at the team level.
Usually what happens is someone who is someone at the team who is just fed up with a not great status quo drives adoption of it.
And other team members see, there's obviously initial skepticism because there always is whenever you try to introduce new tooling.
I'm as guilty of this as anyone.
But then there's that aha moment of, oh, things got more rigorous and faster.
That is a trade-off I will gladly take.
Yeah.
So very often if CI runs pants, and that is therefore in some sense the definition of correct quality control checks, because whether it's testing, linting, packaging, etc.
Because you can't merge until you pass CI, there's strong incentive there for you to use the same thing that CI is doing on your laptop.
Because if you get that to pass on your laptop, it is overwhelmingly more likely to pass in CI, which just gets you to merge faster.
Yeah, I guess it depends a little bit on how you work as a team and source control, right?
If everyone can just commit to main, it's much harder to have that.
But if you've got to go through kind of a get flow, like you work on your branch and then you merge it into main when it's approved and CI passes, well, then all of a sudden, if CI is not passing, you're not merging.
And yeah, then it trickles back until it gets fixed.
I think this is a big part of Python, quote unquote, growing up as a language like now, again, it's not fancy shell scripts, it is a workhorse language that people are building massive businesses and systems and data science capabilities out of.
And you need to, you know, that comes with responsibility to be rigorous about quality control.
And essentially, you know, having really good CI, having really good iterative development practices is something that is really important for these growing repos.
And it's why pants exists.
It is to make that much, much easier and much, much faster than it would otherwise be.
If you are sort of not running tests, not really running any checks, pushing directly to main, you know, because, you know, historically, Python repos were these tiny toy things that you could do that in.
You know, you're asking for trouble sooner or later.
So I'm asking you, how do I get this tool that applies all these, automates all of these engineering best practices?
And you're suggesting that maybe you start by, start at the core and work your way out, right?
Like, like just the way that you work together as a team through source control, like you formalize that a little bit, then everything else becomes easy.
I think so.
I mean, having CI that is the, you need some way of saying what is correct.
You need some way of saying, if this CI is green, that means you can merge this change.
If this CI is green, it means that you can deploy to production.
You need some way, automated way of saying this code is good.
Pants makes it very easy to build that ability.
And once you have that, you never want to go back.
There is a hurdle you have to, you know, it's less convenient than not doing any quality control, but you sort of have to.
Well, it's less convenient up front.
It's less convenient up front.
It's easier to just not worry about it.
But you.
It is.
But as soon as you spend the whole weekend trying to figure out why the thing doesn't work and you're supposed to release it and it turns out it was somebody else's problem and they didn't test.
And then like, then all of a sudden that, that little bit of work up front didn't seem so big.
Nobody goes backwards, right?
Nobody goes in the direction of fewer quality control checks.
There is a point in the evolution of your repo where you start adopting them and you just adopt more and more of them.
And right.
You don't go.
It's a rat.
It's a one way ratchet, basically.
And with good reason.
In my mind, all these conversations I've been having, I've been around like teams, I guess, maybe seated by the idea of you talking about it coming from places like Twitter and so on.
What is the pants story for open source repos?
Like if I was in charge of HTTPX, I'm not.
But if I were, what does pants offer me?
So we do, we're starting to see open source repos adopt pants now, tends to be the larger ones where things like how can I speed up tests become a question even in that regard.
One thing that we haven't talked about really is security and sort of protecting your own software supply chain, especially if you're an open source project where you are typically part of other people's software supply chain.
So one of the features of pants is it has very strong support for lock files where a universal lock files that are valued across platforms that lock down.
Essentially, you generate a lock file that contains pins every single transitive dependency, including these SHA-256s of all of the wheel files.
And pants then knows how to very efficiently build virtual environments out of the subset of those that is actually necessary in any given situation.
So if a test only needs some small subset, it will only use those.
The advantage being that that test gets invalidated a lot less when, because it doesn't get invalid, the results don't get invalidated if an unrelated requirement, upstream requirement changes.
So even for smaller repos or for, you know, open source repos, apart from all the other benefits, one benefit that I think is worth looking at is lock files and just locking down your supply chain.
It means you don't have like the left pad issue, things like that.
You are much more robust to your build is much less impacted by changes on PyPI, by changes in the world at large.
Yeah, in the homepage, it says it has out of the box support for multiple dependency resolvers in addition to these lock files, right?
So is this like your own private PyPI server that you can limit what goes in there?
What does that mean?
Well, you can.
I think what that was referring to was that you can have multiple of these lock files.
So you have a large code base.
You might have different parts of it that genuinely need conflicting dependencies.
But you can sort of say, OK, here are like two or three lock files that you are allowed to, you know, you have to pick one for a piece of code or a piece of code can be compatible with multiple, but you have to pick one when you come to build a binary or something like that.
So, for example, it's pretty common to have, you know, here is a lock file that is for my web application code.
And here's a different lock file for my data science code, because there are just conflicts between them that can't be resolved.
There may be no reason to install JupyterLab on your FastAPI server, right?
Well, that wouldn't happen anyway, because Pants would know, even if you had a single lock file that included, say, you know, NumPy, Pants would know that nothing in your web app imports NumPy, so it wouldn't bring it in.
This is more when you actually have multiple lock files.
Yeah, so Pants is very good about shaving down the dependencies, both the internal and the external ones, to just what you actually need.
But where multiple lock files comes in is when you have conflicts, when your code base is large enough that you genuinely cannot have the entire code base be in lockstep on a single set of dependencies.
We don't encourage that.
It's not a great way to be.
It's better if you can have a single, consistent resolve across your entire code base, but it's not always possible.
And this is an example of where we designed for the world as it is and not the world as we would like it to be.
Yeah, that makes a lot of sense.
I mean, if one of the APIs is written in Django 1 and the person who built it left and there's no reason for it to change, like, just don't touch it.
Just leave that alone over there.
But the other part needs to use, you know, newer libraries and sure.
Yes, that's a great example.
Yeah, cool.
All right, Benji.
I think we might be getting short on time here, but let me close this out with one final question.
So you talked a lot about the caching and the parallelization and how, like, the dependency understanding.
So if I want to run these tests, I can just say, run since this last get a tag or whatever, a shah or whatever it is you're going back to.
What is your personal workflow or common workflows you see for managing that?
Because at some point I'm like, okay, the stuff up to here is good.
Now I want to, it's been a few days.
I want to move forward.
I know the older stuff is good and we're not changing it.
Like, how do you sort of evolve this developer workflow sort of history?
What's your workflow there?
I rely very heavily on the Git comparison logic.
So I should mention I do not code very much anymore because I'm now, I'm the co-founder of Toolchain, which is a company that actually provides SaaS and support and services around builds, Python and otherwise.
And obviously that's where a lot of the pants expertise comes from.
So we provide things like remote caching, remote execution as a service.
So I don't code that much anymore.
But, you know, occasionally when I do, I rely very heavily on the Git diff functionality.
So my command lines are just basically, and one thing pants has is macros where you can create these, sorry, macros is something else.
What I was actually referring to, but I can run like pants green.
I can't really say, but I'm going to use my pants green.
I can't really say, but I'm going to use my pants.
I'm going to use my pants.
And what you can actually do is run this in a loop.
So you can have pants just sort of watch for file system.
It watches your file system for changes and automatically rerun that logic every time you save.
So often by the time I tab into my terminal, those checks have already run or are at least running.
Yeah.
Okay.
That's my workflow.
This command alias is a cool idea as well.
I'm sure people will dig that.
All right.
Well, congratulations on Toolchain.
Thank you.
It seems like a cool thing to be working on and clearly builds on a ton of work you all have been doing.
Thank you.
Yeah.
We basically feel both on the open source side and on the company side that you should not have to work at Google or Microsoft or Facebook to have a really fast, stable, powerful build experience.
You should have that when you're a 20 person company and when you're a 200 person company and when you're a 2,000 person company.
You should not have to wait to be a 100,000 person company to get that.
Yeah.
You should be somebody whose job it is to set up CI.
I mean, their whole job, not just something they do as part of their job.
Yeah, I guess that's the other side of things.
I see about the developer workflow.
What does it look like?
It's like, let's suppose I have a GitHub and I'm using GitHub Actions as my CI.
How do I get pants to work over there?
So that's an interesting area that we are looking at more and more closely.
And we will have some interesting announcements about that over the next few weeks.
And just a heads up, this episode will probably, for people not watching the live stream, will be out probably in three or four weeks.
So it might actually be real as they hear these words.
We'll see.
Maybe.
But it is very easy to set up GitHub Actions or CircleCI or BuildKite or whatever you're using to run pants commands.
And those pants commands in turn take away a lot of the or handle a lot of the concurrency and caching concerns that normally you would have to really mess with.
You'd have to really drill into your CI config in order to get.
So it essentially makes it much, much, much easier to configure CI because the complexity of, well, how do I get caching?
How do I get concurrency?
How do I speed things up?
Is handled automatically by pants instead of you manually having to write tons of YAML or whatever your CI providers config is in order to get that concurrency.
Here, there's a lot of heavy lifting going on where the system itself is analyzing your code and saying, oh, here are opportunities for concurrency.
Here are opportunities for caching.
Whereas today, with CI of all kinds, CI workflows of all kinds, either you do that yourself or you vary manually or you don't get it.
Interesting.
And maybe as part of the caching, you just say, like you described for the developer workflow, right?
Everything other than, you know, compare that against main and now run it on that diff.
Exactly.
And CI is basically, you set up CI to call pants.
Pants does its magic.
Correct.
Answers come out.
So you don't have to write tons of a CI config because a lot of, so much of the reason you would have to do that is now handled by pants itself.
Yeah.
Awesome.
All right.
Well, very cool project and definitely something to be checking out.
Now, before you get out of there, out of here, but final two questions.
If you're going to write some code, even if you do a little bit less these days, what editor are you using?
I use PyCharm.
Yeah.
Actually, technically I use IntelliJ with the PyCharm plugin because of just habit of, I used to write JVM code and I never lost the habit, but effectively PyCharm.
Yeah.
Right on.
Cool.
And then notable PyPI package.
I really like click.
We don't use it for various reasons.
We need like a lot of control over the CLI, but I really like click for just cobbling together cool tools that have really good CLI interfaces.
Excellent.
And let me hijack the end here just for a moment.
Maybe I should have asked you before to install pants.
It's not pip install pants, is it?
Nope.
It's, so if you go to our website, pantsbuild.org, there's very simple steps for walking through it.
But essentially there's a wrapper script that does things like install pants for you in a virtual env and keep it up to date.
So you don't have to worry about where is this virtual env, how to, which version of pants is in it.
It will look at the version that's in your pants config file.
There's a pants.toml file that contains a bunch of pants config.
One of them is which version of pants is this repo supposed to be using?
And the script will make sure that is the version being used.
Yeah.
So you don't pip install it.
You run this script and it does a bunch of magic on top of the vanilla virtual env experience.
Fantastic.
Okay.
Yeah.
Just pantsbuild.org slash docs slash installation and off you go.
All right.
Thank you so much for being here.
Final call to action.
People want to get started with pants.
What do they do?
So pantsbuild.org and probably one of the best resources is our Slack channel.
So if you go to pantsbuild.org and click on community on that community link at the top,
it'll take you straight into like how to come chat with us on Slack.
So obviously you're going to try and get started without that, but it's, we have a very friendly,
helpful community that firmly believes that there are no bad questions, only bad documentation.
And so Slack is a great place to kind of sample the community, come chat with us, tell us about
your needs, tell us about how pants can meet them or how it can't meet them.
It's open source.
And we have a lot of contributors from all sorts of companies and all sorts of organizations
and all sorts of teams who started that way and got really enamored with what pants can
do and got really involved both in improving the developer experience at their organizations
and also in improving pants itself.
So we really, best call to action is come say hi.
Congrats on cool project and thanks for coming and sharing it with us.
Thank you.
It was my pleasure.
You bet.
Bye.
This has been another episode of Talk Python to Me.
Thank you to our sponsors.
Be sure to check out what they're offering.
It really helps support the show.
Listen to the Local Maximum podcast.
Learn about topics as diverse as the philosophy of probability and Elon Musk's next move.
Just search for Local Maximum in your favorite podcast player.
Starting a business is hard.
Microsoft for Startups, Founders Hub provides all founders at any stage with free resources
and connections to solve startup challenges.
Apply for free today at talkpython.fm/founders hub.
Want to level up your Python?
We have one of the largest catalogs of Python video courses over at Talk Python.
Our content ranges from true beginners to deeply advanced topics like memory and async.
And best of all, there's not a subscription in sight.
Check it out for yourself at training.talkpython.fm.
Be sure to subscribe to the show.
Open your favorite podcast app and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play,
and the direct RSS feed at /rss on talkpython.fm.
We're live streaming most of our recordings these days.
If you want to be part of the show and have your comments featured on the air,
be sure to subscribe to our YouTube channel at talkpython.fm/youtube.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
Thank you.