Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
This is episode 159, recorded November 26, 2019.
I'm Brian Okken.
And I'm Michael Kennedy.
And this episode is brought to you by DigitalOcean.
Thank you, DigitalOcean. More about them later.
Michael, what are we talking about right away?
You know, I'm a big fan of type annotations, and I don't know how I missed this one.
I can't remember what I was reading.
It was something we covered on a show recently, and it was talking about the final type annotation.
I'm like, wait a minute, what? There's a final?
As in, with object-oriented programming, you know, there's like abstract methods, virtual methods that can be overridden, protected types.
And some of those things appear in Python, abstract method, for example, but others don't, such as protected or internal.
Another thing that, until very recently, did not appear in Python is a final type, saying this class cannot be overridden, or this method cannot be overridden in a type hierarchy.
But now you can.
Oh, cool.
And this is actually already in Python 3.8, if I'm reading this right.
So, this is PEP 591.
Its status is accepted, and its Python version is 3.8.
So, I have not actually had a chance to test this out.
But, yeah, it looks like it is part of it.
And, you know, because it has to do with typing, of course, Gita Von Rossum is the BDFL delegate, which is kind of interesting.
He's his own delegate, in a sense.
But now the steering council is there.
It's a little bit different.
But, yeah, so he was part of this, and it adds a final type.
So, I can say this class cannot be derived from.
This method should not be overridden.
And those sound pretty straightforward.
But as far as I can tell from the use cases they put in the PEP, it's something that is very, very close to a constant value as well.
What do you mean?
So, one of the things I can do is I can put an at final decorator on a class, and then if I try to derive from it, the type checker will give me an error saying you cannot inherit from final class, whatever, right?
Yeah.
If I put it on a method, and then I try to have a derived class that replaces that method effectively, like implicitly overriding it, I'll get an error.
It says cannot override final method foo, whatever, right?
It was first defined.
But I can also say that there is a variable called rate, which is final, and it equals 3,000.
And if I try to set it to another value, like rate equals 300, the type checker will give me an error, say cannot assign to a final attribute.
Okay.
Or I can go to a class, and I can put that on a field, and if I try to change the field, like if I have a class called base, and it has a default ID, if I say base.defaultID equals something other than what it was initially set to, error cannot override final attribute.
So the error doesn't say this is a constant value, you cannot do this, but it's like a constant.
Yeah.
Okay.
That's nice.
It's interesting, right?
Well, I guess it totally makes sense, because overriding, like deriving from a class or something is kind of similar.
Certainly changing the name, like the redefining the method in a base class is like replacing the name of it.
And so the implementation seems to just catch straight up attributes as well, just probably with not much extra work, if any.
Yeah.
So this is all the stuff that I'm telling you, this is all type checker magic.
This is not real, right?
This is not runtime behavior.
Right.
But, you know, I suspect that tooling like PyCharm, for example, if you tried to set that, it would like turn it like yellowish and say, warning, this is a problem here.
And already, if your editor tells you not to do it, your continuous integration maybe checks these things.
I think you're in a pretty good place.
And I think that more and more we're going to see as the years come on that people's workflow is just going to include type checkers with their code, with large projects at least.
Yeah, at least with large projects.
I agree.
Cool.
Well, I'm pretty excited about this.
I was really surprised to see that was in 3.8, but I'm happy to spread the news about PEP 5.9.1.
How about you?
You've got some numbers that are incrementing as well, huh?
Yes.
So, Flit, have we talked about packaging?
I know.
I don't think we have enough.
Not enough.
Let's keep going.
I'm almost positive we've covered Flit before.
Yeah, we certainly discussed it, if not made it its own pure topic.
We've definitely talked about it.
Right.
So, one of the beefs I had with Flit, which was just a minor thing.
So, Flit makes it easy so that you can, like super easy.
So, if you've got some code that you want to share with somebody, you just install Flit and say Flit init, and essentially it does the right thing to create a package for you.
You don't have to read up on setup tools or anything.
It just kind of works.
Oh, that's interesting.
It's like npm init, sort of.
Okay.
I don't know what that is, but I'll believe you.
That creates a good job of like an npm package.
Yeah, yeah.
The news right now is Flit 2 is here.
So, when initially playing with Flit, I noticed a lot of quirks with it.
So, for instance, you couldn't use a source directory to put your source code in it.
Your package needed to be a top-level directory or just a module.
That was actually a pull request that I did to try to get the source directory added to Flit.
And now it's in.
So, it's in 2.
But it also wouldn't play.
That's awesome.
Yeah.
So, when playing with it now also, it used to be that it really assumed you were going to be in a Git repository.
That's fine.
Except for when you're just playing with stuff.
Sometimes you're not.
You're just trying.
Yeah.
I want to just try this out.
I'm not committed yet to this even working.
Let's just see what happens, right?
Right.
Flit now does work without if you're not in a Git.
It determines what files to include in a package with Git stuff or with, you know, what's in Git and what's not in Git.
And I don't know how it works when you're not in a Git repo.
But right now, it does work if you're just playing around.
If you don't have anything checked in, it still works.
And that's pretty handy.
I mean, I definitely want everybody to use version control.
But if you're just trying this out, you can now.
And it's really cool.
And there's a whole bunch of improvements.
I'm linking to the release notes or the history.
It's just sort of, if you've tried it before and were frustrated, try it again.
The caveats I'd like to say is this kind of a lightweight packaging system, it does not work for compiled code.
So, it's not built yet to deal with compiled parts of it.
Right.
If I had like some Cython bits or something, it doesn't deal with that.
It doesn't.
And then there's a couple other reasons why you might not want to use this.
But for, I think, the 80% case where people are just trying to share some Python code with each other, this is the way to go.
Okay.
That sounds super cool.
Yeah.
That's what I love in the second version is your email address is optional now.
It used to be required.
But you're not required to put an email address in PyPI.
So, why require it for these tools?
Yeah.
That makes a lot of sense.
Yay.
So, now my big beef with the split not supporting source is I'm done with that beef.
You know what?
This is a super cool example as well, right?
Like, it's one thing to just complain and say, you know what?
This thing is crappy or it doesn't work the way I want or something.
It's another to say, and I'll help to make a difference, right?
So, like, the reason it supports it is your PR was merged in, right?
That's awesome.
Yeah.
And it also, it doesn't add any, I didn't add any flags, didn't add anything.
It's just within the init part of it.
It detects that your code is in a source directory and it just uses that.
Yeah.
Super.
Nice work.
Do you know what else is cool?
DigitalOcean.
DigitalOcean is very cool.
DigitalOcean is making Kubernetes easier with their DigitalOcean container registry and one-click
apps.
After building your app into Docker containers, you'll often want to store container images in
a centralized location called a container registry.
From there, you can pull images into a Kubernetes cluster or a VM, whether it's a development,
testing, staging, or production environment.
While you can post your containers' images into the open internet freely using services like
Docker Hub, clearly you don't want to do that with confidential software or, you know,
your own private stuff.
So, DigitalOcean introduced a new managed service called DigitalOcean Container
Container Registry.
And it's now available in early access mode.
So, DigitalOcean Container Registry is simple, private, secure, and fast.
And you can get started using it by going to pythonbytes.fm/digitalocean.
Cool.
I feel like this next item that I want us to talk about, I feel like we talked about it
before, but I went back and I searched and I couldn't find anything about it.
So, if we covered it like three years ago, we're going to cover it again.
Nonetheless, it deserves to be covered because it's really cool.
This comes to us from Andrew Simon and it's called Pint.
So, how many cups is in a pint?
Or do pints go into cups?
Is there, like, how many gallons go in there?
And if I had to convert that to liters or milligrams, like, what would, like, I don't know.
All these questions are completely unknown to me without, like, some chart and a calculator
or Google.
And I would suspect they are to a lot of folks.
Mixing some form of units, even if they're in the same system, like meters and millimeters,
can be tricky, right?
So, this pint thing, its job is to basically apply units to numbers and calculations in Python.
Okay, so, I'm sure you took physics and, you know, in physics or maybe even chemistry,
like, your professor would tell you, like, you cannot just tell me the number is seven.
You have to say seven what?
You have to put units on this number or this number doesn't really tell us what the answer is
or what we're working with, right?
And so, pint lets you do that.
It has all these different types of measurements.
It has, like, energy and, you know, like, joules and it has distance and weight and all these
these different types of things.
Even wavelength.
It'll help you, like, convert wavelength types of measurements and stuff.
So, if you've got some numbers you need to add together, like, for example, it's super easy to add
two meters and five inches and get the right answer in the units that you want.
Oh, that's cool.
Yeah, super cool, right?
So, I'm linking to basically a Python document that has a TXT ending on GitHub.
So, read that however you want when you get to it.
It's a little unformatted.
But it shows you all the different units and types of units that you can work with, right?
It knows what a decigram or a decimeter is and all those different types of things.
So, I just want to share a quote.
It's on the homepage there that talks on the pint.
Read the docs.
So, it talks about the Mars Climate Orbiter.
And it said the MCO has determined...
This is an orbiter that went around Mars until it didn't go around Mars anymore and it hit Mars,
I believe.
It met Mars in an unfortunate way.
It said the MCO Mission Investigation Board, MIB I'm guessing, that's what that stands for,
has determined the root cause for the loss of the MCO spacecraft was a failure to use metric units
in the coding of the ground software file, small forces, used in trajectory models.
Specifically, the thruster performance data in English units instead of metric units
was used in the software application titled SM underscore forces.
Hence, orbiter meet planet.
So, yeah.
You know, this is not the type of code I write a lot.
So, it's not directly useful for me, but I've studied science a bunch.
And it seems if it is the kind of code you write, it's very simple and very powerful.
Yeah, one of the things I like about it is it's not the units separate so that you can look these up.
It stores the values.
It just has values with units associated with it.
And so, you can pass them around and use them in other places.
And all the math operators work on it.
And it's, I mean, if you really want to, I mean, you kind of have to know the units anyway.
But one other way to do that people have often used is like suffixing variable names with what the units are.
But then that's, there's nothing telling the software that it has to comply with that.
It's just, it's just convention at that point.
But so, if you, especially with mission critical stuff, I think this is a really great idea.
Absolutely.
So, the way you would create like three meters is you would create an instance of a unit registry.
And then you would just take the number three times meter.
Yeah.
And now it's a three meter quantity.
So, they override what the multiplication thing means.
And yeah, it's pretty cool.
That's clear.
You can add different units together like meters and centimeters together and it just works right.
And that's great.
Yep.
Nice and simple.
Yep.
Speaking of simple.
I gotta say that the unit thing that you looked at, you linked to, it has, I didn't know this, that yada is 1 times 10 to the 24th.
So, yada, yada, yada is a really big number.
I had no idea.
That's a huge number.
How interesting.
What a cool piece of trivia.
Yeah.
Okay.
Speaking of a bunch of numbers and great things.
We're gonna take a look at some pytest plugins.
So, Jeff Triplett wrote an article called Eight Great pytest Plugins.
And there was even some fun stuff for me.
I'll just list them quickly.
There's a couple that I'll highlight.
So, pytest Sugar.
So sweet.
It's just a fun one that like changes the output.
But it isn't just fun.
It like changes the output so it looks kind of nice.
You get green check marks and stuff instead of the dots.
Add the progress bar.
Yeah.
Progress bar.
But it also shows failing tests instantly instead of waiting to the end or something.
So, that's nice.
It's cool.
pytest-Cov.
It hooks into the coverage so that you can, you know, more succinctly check your coverage on your code using pytest.
I use that.
It works great.
The next one I want to, which I hadn't heard of before, is called pytest-Picked.
And this is like a brilliant idea.
So, if you've ran your pytest code, you know, you think your stuff is good.
But what this one does is you're working on your code.
And if you're using Git, you've got modified and unstaged and uncommitted code within your repo.
So, that's the stuff that probably the new bugs are in.
And so, what pytest-Picked does is it only, it tests files that, it runs tests that use the files that have been changed since your last commit.
That is super cool.
It probably runs your test code that have been changed since your last commit.
But what I would love to see, and maybe it does this, you tell me if you know, is if it would look at the coverage data and it would rerun the tests that were covered by your tests.
The files that were covered by your tests but then changed, it would rerun those tests that covered it.
Oh, did I get it wrong?
Does it just run?
I think it just straight up runs the files.
It's just like if your tests have changed.
Yeah, I'm pretty sure.
It says the tagline is runs the test related to the unstaged files.
So, not sure.
Yeah, yeah, not sure.
I'll have to try that one out.
Report back.
Yeah, we definitely got to try it.
My first impression from looking at it is it runs the tests that were changed, not the code that was changed covered by the test.
But, yeah, we'll report back.
Both of them are interesting.
They're both very interesting, yes.
They're like already, I think it is a super cool idea and I love it.
If it does the second thing I said, then I'll love it even more.
Yeah, okay.
The next one is pytest InstaFail.
Modifies the default output so that failures show up immediately.
Right now, if you run pytest, if you just run it with no options, you get a bunch of dots for all your passes.
You will see the F for the fails, but you don't get the output right away.
Like what the traceback is.
And so, if you really want to like start debugging before your test suite is done, InstaFail might be the thing for you to show your failures right away.
The details of your failures.
Now, for people that really think that pytest is already giving you too much information, pytest TLDR is hilarious, but it's actually quite useful.
And it will kind of remove some of the stuff from the pytest output.
Some of the boilerplate that comes at the top and bottom and also just kind of reduces the output.
It's kind of nice.
And this is by Freakboy.
Kenneth, I'm going to get this wrong.
Keith Russell McGee.
Yeah, that's it.
Now, next one is pytest XDist.
A lot of people think of XDist as the way to run all your tests in parallel.
You can run them on multiple processors.
The surprising thing is you can also run them on not just multiple processors, but multiple instruments or multiple machines.
You can have them spawn into other computers to run tests, which is really cool.
But you can also do things like loop on fail and just perpetual.
You can just have these things just keep running.
So, that's pretty cool.
That is cool.
Just periodically just say, try it, try it, try it until it turns green.
Yeah, especially if you're actively working on a fix, why not just have that pop up whenever it's done?
Nice.
The last two are pytest Django and Django Test Plus are both things that will help you if you're testing Django,
which is not surprising that this came from Jeff Triplett because he's a Django guy.
Yeah, very cool ones.
I like these.
Although, I feel like you cheated, Brian.
I mean, we're supposed to cover like six things each show, and here you've covered eight.
Eight great pytest plugins.
Come on.
Like, who would do that?
You know, I told you I was a sucker for link bait articles.
So, listicles.
Yeah, for sure.
Well, the next one I have is 11 new web frameworks.
Oh, and you're giving me a bad time.
Not for long, though.
No, I think it's great.
It's cool to touch on a bunch of those little things real quickly.
Now, people know that I do a bunch of web development, and I'm a fan of web frameworks.
And for a long time, we had kind of the mainstays, Blast, Django, and so on.
But recently, and I feel like two things, both the type hints and the async-capable ASGI servers,
those two things have created just like a blossoming of all these different types,
because they're like, well, if we've got to rewrite it so that it supports async and await,
or if we're going to rewrite it so I can use type hints to like grab stuff out of the query string,
let's just go crazy and create all these new frameworks.
And well, 11 new ones is what we get.
Actually, more than that, because there's some that are not listed.
Some we've spoken about, some we haven't spoken about, but I've heard of,
and some I've not even heard of.
So it's pretty cool.
I'll just go down the list really quick.
One of the things that's interesting, if you look at a lot of these frameworks,
a lot of them are Flask-inspired.
like, you know, you create an app, and then you do app.
you know, decorate app.route to define it and stuff like that.
A lot of them have adopted the Flask API without actually being Flask or coming from Flask.
So anyway, so the number one is Sanic, which is a web server framework meant to go fast.
And this one is mostly focused around enabling async and await.
That's pretty cool.
Probably the most widely used, at least in terms of other projects,
for the ASGI, the async type of frameworks, is Starlet.
So Starlette is cool.
Comes from, I believe, Tom Christie and folks who are involved with the Django REST framework.
And it's a lightweight ASGI framework, which is great for high-performance async and await services.
And you can either use it as its own web framework, or it's interesting as a foundation.
For example, Responder is built atop it.
I believe FastAPI may be as well.
Yeah, I think so.
Yeah.
So there's a bunch of things that are derived from it.
That's pretty cool.
And both those first two are Flask-like.
A Masonite I had, Joseph, from the Masonite team on Talk Python not long ago.
And it's interesting.
This is not an async and await framework.
It's like a standard framework like Flask or Django, at least at the moment.
But what makes it unique is it has this command line tool that lets you do things to the project called Craft.
So the Craft CLI is like what makes this kind of unique.
That was a really good episode with that interview.
And I like the example of somebody bringing in good ideas from other languages and helping out the Python community with that.
Yeah, thanks.
I agree.
It was definitely fun to talk to Joseph.
So, for example, like with a lot of these projects, you create the project and then you're on your own, right?
It's like, okay, well, I use maybe cookie cutter or some other technique to create the project.
And now I've got to write every little bit.
But with Masonite, you can actually go and say, now add this model or go add, you know, these other things.
And it'll continue to like let you evolve it using these sort of starter cookie cutter type things.
So it's cool.
FastAPI.
If I was building an API these days, I would definitely, definitely look at this.
Fast modern framework for building APIs with Python 3.6 based on type hints.
That's cool.
Responder.
This is from Kenneth Wright.
It's based on Starlette and its primary reason for existing is to bring the niceties both from Flask and Falcon over into a single framework.
That's cool.
Molten, which is a minimal, extensible, fast framework for building HTTP APIs with Python.
And it's sort of magic.
One of its magic things is it can automatically validate requests according to schemas.
So you're building an API.
It takes a JSON document.
It can validate that by saying this is what this method takes.
It takes an integer and it has this thing in the JSON document and so on.
It's pretty cool.
Jopronto, another one of the async and await frameworks.
This one's based on uv loop and Pico HTTP parser.
So it's super, super fast.
Like basically its foundation is all C.
Klein.
Have you ever heard of Klein?
No.
Me either.
But apparently it's a micro framework for Python.
And it's incredibly, it's got an incredibly small API like bottle or Flask.
Speaking of Flask, there's Cort.
This is the one that's closest to Flask because it is literally a superset of Flask.
It's so compatible.
It even takes like Flask extensions and just runs those.
But the difference here is, is it adds async and await to Flask.
So if you have a Flask app, you do a find and replace the word Flask with Cort.
And now you can use async and await and Flask.
That's pretty cool.
That's cool.
Blacksheep.
We talked a little bit about that.
This one is inspired by Flask in ASP.NET Core.
One of its bits of magic is it automatically supports binding request values into variables,
either by convention or type annotation.
So I could have a view method and it takes a username and it takes a product ID.
And I could put a little decorative that says the username comes from, I don't know, a cookie or something.
And the product ID comes from the query string.
And it'll automatically go and pull those all together and just pass them as arguments.
That's pretty cool.
And finally, wrap this up, is Cyclone.
Another one I have never heard of, but it's a framework that implements the Tornado API
and the Twisted protocol to bridge Tornado's Elegant API and Twisted's Event Loop, enabling
a vast number of protocols.
So very, very cool.
Yeah.
So unlike my list, you should not use all of these at once.
No.
Yeah.
Your list would be great.
If you try to use all these at once, yeah, you're just going to mess things up.
It's not good.
Like pick one or maybe two.
Maybe if you have APIs and you've got a web framework, but you probably don't even need
to do that.
Just pick one.
Or you could end up with like crashes and exceptions.
All sorts of error messages.
Yeah.
And one of the things that there's an application I'm thinking of doing that I assumed I would,
I don't want to do, go crazy with the micro, micro architecture.
What are those things called?
Micro frameworks?
Not the micro frameworks, but like the whole bunch of microservices.
That's it.
Oh, yes.
However, things like FastAPI and stuff make it so easy to write the API part that I am
thinking about doing like a two, two level thing of doing a FastAPI and then a, and then
a web interface based on that.
It's just two services.
It seems totally reasonable.
Yeah.
It seems fine.
And with engine X and stuff, you can put it under the same domain and just put like proxies
to different parts of your app based on like slash API or not slash API.
Oh, cool.
So the deployment is really easy.
It's a good thing I have friends like you.
Yeah.
Yeah, that's right.
Happy to help.
So next up, I want to talk about exceptions.
Like I am exceptional and you're exceptional.
We're all exceptional.
Everyone's special.
We're all snowflakes.
Yes.
This is a nice article that just came out this November called raise better exceptions
in Python.
So this is just sort of a, I guess, kind of like a public service announcement, actually
kind of a nice article though, about when you're raising exceptions, it's, you know, you
throw an assert in sometimes to be like that.
I should really never get here, but exceptions are not really unexpected things.
There, you should be, your software should handle it.
It's really bad if you're, if your software is not handling exceptions at the top level.
However, often exceptions will happen if like you're raising from a trial, you try some stuff,
you grab a value error or something, and then you raise a more meaningful exception.
That's a pattern that's often used.
The article's really pointing at just don't put like f-strings with value stuff within your, just all within one string as a value error or any sort of, just don't just like try to bundle it all together.
The point is most exceptions, unless you've mucked something up in the init, most exceptions take a unlimited number of parameters.
So if you want to raise an exception with a whole bunch of values for your exception handler to, to be able to introspect and use, just put them in, put them in more parameters in the list of the constructor to the exception.
That's super cool.
And I honestly, I didn't know about this.
This is great because to the example is if I raise a value error and the message is the value is too small, it's like, okay, great.
So now what?
Maybe you can't even get back to like what the value was because the way, you know, it got passed around or it wasn't in a variable.
So what can you like report on that value?
Could you log the value?
Whatever, right?
But if you can just say, here's the message, comma, thing one, thing two, thing three, thing four, and it just appears in the exception.args later and you can deal with it in your catch clause.
It's great.
Right.
And some people will realize that, but not realizing that you can put them as parameters, but realize that you want to know the value.
So they'll try to put the value in a string, but that depends that it depends on the wrapper function or the stir function being valid.
And maybe that's the thing that blew up in the first place.
So, yeah.
Exactly.
It's simple, but it's going to be really handy.
Yeah.
Love it.
All right.
Well, that's it for our main items.
You got anything extra you want to chat about quick?
Yeah, I did.
It showed up on your list, but I'm going to bring it up anyway.
So I was reading around on realpython.com and I came across this thing.
I don't know, there was this guy that was being interviewed.
It said, a Python community interview with Brian Okken.
Yep.
I did that thing.
Awesome.
That's cool.
Yeah.
So if people want to learn more about you, they can go check out this interview on real Python, right?
One of my favorite questions and answers is the question of, how did you get into testing?
And really, I never did.
I've always been a software engineer.
So that was a fun question to answer.
That's cool.
Anything else?
Yeah.
I got two more things I want to talk about.
One of them comes from Brett Cannon, sort of.
It also had you appearing on this little list of mine that I've got.
So Brett Cannon put out a poll and the poll said, if you typically keep your virtual environment locally with your code, as I do, like so at the top level of your project folder, what do you call it?
Is it venv?
Is it dot env?
Is it dot venv?
Is it something else?
And so on.
And that's pretty interesting.
You can see the polls straight up.
No dot venv is what came up the most.
That's what I've migrated towards these days, mostly because some of the tooling works better than the hidden ones or dot env.
But, you know, you've got some replies in here and all sorts of stuff.
But the one that caught my eye the most, and I think maybe you commented on it, was from Brian here, as in Brian Skin.
And he said, I actually use the ability to change the prompt name, right?
So normally when you activate that virtual environment, it would just say parentheses venv.
And you're like, okay, super.
So something somewhere in my entire computer is different about Python and but which, right?
But if you do --prompt equals, you can give it a name so that when you activate it, it says, you know, like Python Bytes Web App or whatever it is you want.
Yeah, I always use that.
You do?
That's cool.
Yeah, because otherwise all my virtual environments are named venv, and that's boring.
That's quite boring.
So, yeah, it's pretty cool.
And you can even pair that with, like, the read command and then take that.
So when you create the virtual environment, you could set up a script that will ask, what do you want your prompt to be called?
And then it'll just put it into the virtual environment.
So when it activates it, it converts it over to that, which is pretty cool.
So my request is, I haven't actually requested this yet, but I would like it to be the name of the directory that the virtual environment is in.
Not the venv one, but the parent directory.
Yes, that would actually almost always be the right answer, wouldn't it?
Yeah, it's usually my project name.
That's what I want to know.
So that's what I'd like.
And then Al Swigert said, I use venv.
Al said he uses dot venv for the reason that you shouldn't muck with it.
It's just there, but you shouldn't change it.
And I'm frustrated that he's right.
And I think I'm going to try using it with a dot from now on, or for at least a little while and see what I think.
Yeah, the reason I like not having the dot is when I'm in the Finder, if I go over there, I can see, okay, this one already has a virtual environment set up.
I haven't been on this project.
It was in GitHub.
It's been like six months.
I come back to it like, do I need to create a virtual environment?
Or is there already one here?
I just go activate.
In Finder?
You can't see the dot files?
No, it hides them.
That's hidden.
Oh, I guess I use command line more than anything else.
Yeah, yeah.
So if you want to see them in Finder, you have to go into the dot folder.
And then you can say open dot or open that folder.
And then it'll like be half grade out in Finder.
But if you just browse to a project, you won't know whether or not it has a virtual environment if it's a dot something.
Okay.
Anyway, it's not a huge benefit, but that's why I kind of stopped using the dot, which I had been before.
So for the subset of people that are on Macs but don't like a command line.
I also like the command line, but I don't exclusively use it, right?
Okay, okay.
All right.
Anyway, this is a whole long discussion about this.
And I thought it was actually pretty interesting, all the threads there.
Yeah.
Pretty cool.
All right.
Last thing.
I told you about a new course last time, right?
Yeah.
Well, since then, I wrote another course and recorded it.
And I think this one's going to be really fun for people as well.
I wanted to write a course for people who are team leads, who are decision makers at their company.
And they're trying to decide or they're working with their team to decide, like, should we adopt Python or is Python the right thing for this project or not?
So I wrote a course called Python for decision makers and business leaders.
If you need ammunition to help sell Python in your organization, or if you want to know, like, maybe when it's not the best choice.
Like, this talks to all those things.
And it also looks at, like, the job market and hiring developers and all kinds of random stuff that I think those groups would care about.
So, anyway, another course is coming shortly.
That's really cool.
Yeah.
Thanks.
I might want to do an alternate course of Python for indecisive cogs.
You might want to work on the name.
It might not, like, attract, like, you know what?
I am an indecisive cog.
I will.
Maybe.
Yeah.
Maybe.
Anyway, it was a lot of fun to put together.
And it'll be out pretty soon.
Okay.
You got a joke for us?
I got something for you.
You can tell me whether it's a joke.
So this comes to us from Daniel Pope.
He didn't send it in.
I just found it on the internet.
And it was his joke.
So I'm going to, at least, it came through him.
So I'm going to share it.
This one is about farm implements.
Okay.
What is a tractor's least favorite programming language?
I don't know.
What?
Rust.
That's bad, right?
Definitely a groaner.
Yeah.
But that reminds me.
So how do you tell when a joke is a bad joke?
When it's fully grown?
Oh, that's a good one.
I like it.
Thanks a lot.
Yeah.
Thanks for being here, Brian.
It was fun.
Bye.
Yeah.
Bye.
Thank you for listening to Python Bytes.
Follow the show on Twitter at Python Bytes.
That's Python Bytes as in B-Y-T-E-S.
And get the full show notes at pythonbytes.fm.
If you have a news item you want featured, just visit pythonbytes.fm and send it our way.
We're always on the lookout for sharing something cool.
This is Brian Okken.
And on behalf of myself and Michael Kennedy, thank you for listening and sharing this podcast
with your friends and colleagues.