Python Bytes - #329 Creating very old Python code
Episode Date: March 30, 2023Topics covered in this episode: Prefix-cache NiceGUI flask-ngrok No-async async with Python Extras Joke See the full show notes for this episode on the website at pythonbytes.fm/329...
Transcript
Discussion (0)
Hello and welcome to Python Bites, where we deliver Python news and headlines directly to your earbuds.
This is episode 329, recorded March 30th, 2023.
And I'm Brian Ocken.
I'm Michael Kennedy.
And before we get started, I want to do a couple things.
I want to thank Microsoft for Startup Founders Hub for sponsoring this episode.
Please listen to their spot.
We've got a very special random guest appearance or voice for that that ad read so that'll be fun um i also if you're
listening to this um i'd like to encourage you to and you've never watched the live show i'd like
to encourage you to watch our uh live show on youtube or streaming um it we usually work today
is thursday but we usually record Tuesday at noon or 11. No,
Tuesday at 11. Yeah, I should have practiced this. Anyway, but welcome. And the people that
are here today are watching on YouTube. Thanks for watching. And why don't you kick us off,
Michael? I got something. I think it'll resonate with you folks. Maybe you already are aware of this. This is news to me.
Comes to us from Brandon Hannigan.
So thanks for sending that in.
And it's an environment variable.
And in and of itself, it's interesting
in that it leads to many more environment variables
you can play with is also pretty awesome.
So this one is about the Dunder Pi cache folder.
So I don't know how you feel about these, Brian.
I'm glad they exist.
I'm not necessarily super glad that they're spread out a bunch of random folders.
So a lot of my projects have many different modules and different folders,
submodule type setup.
And when I run them, they all get filled up with Dunder PyCache folders
with startup PYC,
you know, compiled Python.
Like people might think, I think Python is compiled, but yes, Python is compiled.
It's just then interpreted not, you know, all the way to machine instructions, right?
So those files end up in the Dunder PyCache, which spread throughout your project structure.
Sometimes I want to make a copy of that.
I want to move that around.
I want to zip it up and share it.
And I don't want those things in there.
And so I'll have to go in and search for all those and remove them recursively, which is
not at the end of the world.
But I'd rather they are not there.
Or if they were there, could they just go in a top level thing?
You know what I mean?
Like, could they just go into a single DunderPy cache that understands the whole structure,
not every file being treated as if it's unrelated?
I mean, it's better than it used to be
of having the PYCs right next to the Python files.
Yes, it is an improvement.
But this thing that Brendan said,
you can set the Python PyCache prefix,
which is a path.
Maybe it should be called Python Cache Folder.
I don't know.
Anyway, what you do is you set this
in your environment variable,
maybe in your user account,
maybe in the activation of a virtual environment
if you want it to be a one-off type thing.
I don't know.
Then when Python goes to create these,
it goes, oh, they don't want the DunderPy cache.
They want it over in this directory over there.
And so it'll make,
you can isolate all of your Dunder PyCache stuff
into a separate location on your user profile.
You can go and just blast that away
whenever you feel like.
But most importantly,
it's not within your source code.
If you like zip it up and hand it out
or things like that.
Oh, wow.
Okay.
That's great.
Yeah.
It says, if this is set,
Python will write star.pyc files
in a mirror directory tree at this
path instead of in
dunderpy cache directories within the source tree.
This is equivalent to specifying the dash x
pycache prefix equals
path option. So pretty cool, right?
Yeah, I also didn't know about the dash x
though either, so that's pretty cool.
Yeah, this page that I'm linking to is at
the top, it has all the command line options and then
almost all the command line options have an environment variable thing if you
want it to just be the default all the time and you don't have to set it.
So there's a bunch you can come look through here.
So Python path, you can set Python startup.
So these are the Python commands that will execute whenever you start Python, which is
kind of interesting.
Optimize, breakpoint, debug,
the one we talked about. You can set up a hash seed so you can get repeatable deterministic
hashing. A bunch of stuff is here people can check out. How you look at warnings, how much
warnings you want to see, whether or not there's buffering., you'll see sometimes things like the standard out will come after the
standard error, but the standard error in time actually came after the out, right? Because the
buffering got out of, you know, they hit the buffer at different periods. So you can do things
like turn that off, turn on malloc stats if you want to track that. So there's like a bunch of
things you can come in here and play with. But that think the pyc one's an interesting one especially for people who hand out code you know like if
you're doing like a training or a tutorial and you're like here i want to give everybody this
you got the pyc file again i was just looking through there because i'm surprised that you
can't you can't specify which xkcd comic don't link to but i know when i import anti-gravity
which one don't worry we'll get there cool all
right well that's what i got for this one um the the python pi cache prefix check it out nice yeah
um i wanted to talk about guis we haven't talked about guis for a while
we were on such a kick we were on such a kick yeah but um uh several people have mentioned this to us so we thought we'd cover it
um it's a package called nice gui and normally actually when i think about gui i think about like
actual not web stuff but user interface stuff that's on the desktop but this is a this is a
browser-based thing so this is a um this is a package that's it says it's easy to use python
based ui framework which shows up in your web browser, buttons, dialogues, markdown, 3d plots and more.
What what's cool is you can play with it all before you even try it.
So the the documentation is really great.
And even just here, I thought this was just like a screenshot or something.
Now you can just like this is part of it.
You can move it and interact with it right here in the the first page it's pretty cool um the document full documentation is uh is really pretty
pretty great too i actually want to try to play with this because the the uh the code really looks
pretty easy to write um so for some quick uh maybe dashboards or some quick control stuff that you're
okay with doing through a web browser why not try it it out? And some of these are pretty cool.
I was playing with text input.
So it's talking about validation and stuff.
So you can have some text and you can just start typing
and it's saying, oh, that's too long.
So you can, I mean, this validation is pretty simple
of just checking length,
but you can do all sorts of stuff like email validation
or whatever you want it to do
because it's just like a function that's calling so kind of neat uh you got a validation there
uh knobs knobs are fun um i was playing with the knobs so drag knob and turning anyway uh
all sorts of easy context manager to put it into the page with knob what because with knob
um interesting i wonder why i don't know oh to put the icon inside
it so you basically it looks like you're focusing the the subsequent commands to be within the
container of the knob because you the knob is like a like a circular progress bar type thing and you
can put a volume up icon inside it okay um, just all sorts of cool stuff.
Joystick.
That's really, I don't have a joystick to play with this out, but some interesting naming
there with the joystick.
But anyway, so moving on, date pickers and all sorts of things.
Ooh, that's nice.
Cool.
But UI elements, if you're okay with trying something new, a nice GUI might be right for you. So that's nice cool but ui elements uh if you if you're okay with trying something new
um a nice gui might be right for you so that's interesting isn't it uh you know i when i look at
these types of frameworks that a lot of times i feel like what they say is um html is terrible
the dom is terrible css is terrible let's create a parallel python or name your language equivalent where we put elements
in the web page i'm like they may have their drawbacks but at least you have a ton of tools
and stuff that apply to html and css and all those things right but yeah this one i think there's a
lot of cool widgets and stuff that are here and it looks more like the it's not like we don't like
html so let's make a Python DOM that you create the HTML with.
But rather, how do we make a cool interactive page based on these additional things like knobs and joysticks and sliders and stuff that's not easily part of HTML?
Yeah, and the places where I would really use something like this are, I mean, this is some short code.
So especially internal
tools where or even just stuff for myself if i want to explore some data control like a database
or uh got a bunch of you know controlling some system or something and i want to like quickly
throw something together something like this would be great for yeah just um doing a like a one pager
something to try it out.
I also think these types of frameworks
would be pretty cool to bring into some kind of
Electron JS type thing,
where you're like,
and here's how you make it an app
that doesn't actually look like a web page
and give it to someone.
Yeah, so one of the things they bring up
is great for micro web apps, dashboards,
robotics projects,
like school robotics,
stuff like that.
Smart home solutions.
That joystick thing,
right?
Can drive you a little.
And then the,
one of the,
one of the nice things that I noticed about the documentation is they've got
a bunch of demos.
Oh,
these are the actual demos,
but there's examples.
Where did I find those?
Is it maybe under examples?
Well, anyway, there's a whole bunch of like actual code.
So there's repos around that you can try it out with, um, with the, with different repositories.
Maybe it's just on the front page.
Anyway.
Um, I was impressed.
Oh yeah.
Here we go.
Down at the bottom of the front page, there's like slideshows.
And even if you want to, will this work with fast api apparently there's a fast api uh example uh for just uh some some quick repositories
so you can try it out yourself uh maybe like an admin page type of dashboard thing that you can
play with um yeah there's some open cv webcam infinite scroll for galleries um and i the the the amount of like demos of components
right there but then actually specific examples where you can uh you know with the code with
repos that you can just copy and get started with that's pretty pretty impressive that they put all
that together right off the bat yeah so yeah it looks like it's definitely worth checking out do you know what else is worth checking out our sponsor yes microsoft for startups founders hub thank you for sponsoring this episode
and what was the uh key that you what what how did you generate this code the text remember i don't
recall who suggested it because i had the American football coach motivational speech version variant last
time. And somebody said, well, what if it was like Ted Lasso? So I said, hey, open AI thing.
Here's the Microsoft ad. Could you rewrite it this time in the style of Ted Lasso?
Yeah. So it's an odd episode. So I get the honor of trying to be Ted Lasso, which I'm not going to get the voice, so apologies.
And I did not grow up in the Midwest, so anyway, let's just get started.
Hey there, team. Gather around, because I've got something real special to share with y'all.
Now, you know how much I believe in the power of teamwork and positivity, right?
Well, this opportunity I'm about to tell you is just like the perfect assist to your startup goal.
I'm talking about the Microsoft for Startups Founders Hub, folks.
Now imagine, if you will, a locker room full of support for your startup, especially if you're keen on that there artificial intelligence stuff.
We're talking over six figures of benefits that'll change the game for your team. They're offering you 150k in Azure
credits. And that my friends is like having the best player on the field on your side. And what's
more, the Founders Hub has given y'all a unique chance to access open AIs, APIs, and the new
Azure Open AI API, the Azure Open AI service. It's like having your own generative AI coach to help you come up
with game winning strategies for your applications. Now, I know how important it is to have the right
support. And that's why the folks at Microsoft are also offering one-on-one technical advice,
helping you with your game plan, scalability and security. Plus, you'll be part of a network of
mentors who know the startup world like the back of their hand.
I can't emphasize enough how amazing this opportunity is, friends.
And guess what?
It's open to everyone, no matter what stage your startup's at,
and no funding requirements.
Just take five minutes to apply,
and you'll be on your way to reap in some massive benefits.
So come on team,
let's harness the power of AI for your startup and join Microsoft for Startup Founders Hub today.
Head on over to pythonbytes.fm slash foundershub2022 and sign up. This is your chance to
score big, so don't let it slip through your fingers. And just so you know, the ad you just
heard was written by the same AI you'll get access to.
Ain't that something?
So don't wait any longer and sign up at pythonbytes.fm slash Founders Hub 2022.
A big thank you to Microsoft for supporting this show.
That open AI, that sure is something.
All right.
Speaking of something, let's talk about Ngrok.
Let's talk about Flask. I can't decide. Let's talk about ngrok let's talk about flask like i can't decide let's
talk about both so this one i want to cover is uh an interesting one so i've talked about
ngrok before for those of you don't know like unfortunately their website i don't know what's
gone on but they redesigned it in a way they can't really tell what it does but it's just, anyway. In Grok, what it does is it lets you run a command locally
and then share your web app,
whether that be for an API,
someone needs to talk to the API,
or just the web app itself.
So for example, Brian,
imagine you had created a cool demo of that nice GUI thing
and you wanted to let some people,
you're in a meeting with your team,
like, hey, you guys, y'all should check this out. This is really, really cool. And what you might do
normally would say, well, let's just fire up a screen sharing and I'll drive it around. But
the interaction part of those widgets is really cool. So it'd be better if you could just say,
and interact with this, right? So if you fire up ngrok, you just give them a URL that reverse
SSH tunnels into your machine,
and then they can access it on the internet with their browser, and everyone can play with it live.
Right?
So that's really cool.
I recently used that for I'm just about to release a course called Python Web Apps that fly with CDNs.
Like, basically, how do you do really awesome stuff with CDNs plus Python and Flask
and all those things to make your app way, way faster? Well, in order to put that together and
test it, you've got to let a public CDN get access to your dev machine, which like, how does that
happen? Ngrok is how that happens. Same thing with our mobile apps, like you can see like right here.
We had this problem where some of the data wasn't being passed through as headers correctly
to the server.
And we're like, we cannot figure out
why this is not working.
It's clearly in the headers collection.
Why is Python not seeing those?
And it turns out there was like a weird
case sensitivity issue or whatever.
But I just fired up ngrok,
pressed debug on PyCharm,
and said, all right, try it again.
And then boom, I'm like stepping through,
like on a mobile device, I'm stepping through its interaction with the APIs. I'm like, oh, I see, try it again. And then boom, I'm like stepping through, like on a mobile device,
I'm stepping through its interaction with the APIs.
I'm like, oh, I see, here's what's happening.
And then we fix it, super easy.
All of that is to set up Flask-Ngrok.
So all of those benefits are awesome,
but like what I gotta do is I have to go fire up Ngrok,
go over, do the thing and then come back, right?
So it'd be cool maybe if I could just press go,
either run, you know, Flask run or just go in PyCharm or VS Code
and it would just, in addition to starting up Flask,
it would also start up ngrok
pointing back at whatever the right port is, right?
So basically that's what this is.
You just wrap the app in run with ngrok.
So you get a run with ngrok app.
And then when you say flask run it fires up
the local version but it also fires up an ngrok url that you can share with people oh cool yeah
so not not a huge huge feature because sure you can run ngrok on your own but i think it's kind
of cool like it basically that means whenever you run your flask code your flask app for debugging
or for dev or whatever,
there's always a publicly accessible address that you can share with other people or you can type
into some other tool. I want to validate an RSS feed. I want to have my API, some API client that
is not on my machine, like a mobile app or some other, you know, think if this than that,
or one of those types of things, all those can just come back right in because you always
have this public address available, which I think is pretty cool.
That's pretty cool.
Yeah.
So if that sounds useful, people can check it out.
Oh, man.
Okay.
So I was just thinking, I wonder if random address, because like I need another URL that
I'm not doing anything with, but I was wondering if random address was taken and random address is taken.
Is it random addresses?
No, we have enough.
I've got several that I'm not using.
Yeah, that's awesome.
All right, cool.
Anyway, people can check this out
if they are doing a lot with ngrok.
So by the way, one thing that I think would be interesting,
I didn't see in the docs whether or not this is easy, possible, impossible, whatever. One of the things you can do is you can
set it up so that this random address is repeatable. Otherwise, if you just rerun it,
you'll get a new random address, which you got to keep typing in by doing like subdomain type
things and stuff. You've got a paid account. I don't know if it's possible to have it do that
or not, but it would be cool if you could make it random but not completely random so anyway not complete just
random once and then yeah random once and let's stick with that for a while all right what do you
got for our last one i want to talk about async so um will mccougan i wrote an article called no
async with python no no async async and it it's not, that's confused me, but it's,
it's a really well-written article. There's,
there's times where if you want to take advantage of async you you kind of
have to have async all the way up and down the call stack, right?
Or you maybe that's what it seems like at least to make things sure this all
works. But and so that's actually what I guess textual did at one point is made a sync to all the things.
But textual now is a sync optional.
And so this article discusses how they do that.
And the first part is if you're passing in a callback to if you if you're providing a mechanism for somebody to pass a callback in,
and that callback can, you want it to be either just a normal function or an async function.
He's utilizing the await me maybe pattern that he borrowed from Simon Willison.
So Simon Willison wrote about this a couple years ago.
And he shows, scroll almost to the bottom.
There's this, basically, there's a way to, you have an async function and it calls.
So the caller is async and you're calling something that could be either async or not.
And you, you just call something and check to see if it's a coroutine and then awaited
or don't await it.
Um, and that's, that's pretty much what, uh, will is showing is, you know, inspect the callback, inspect the result to see if it's awaitable or not.
Doing it a little bit different method, but similar sort of effect.
So that's neat.
So you can provide a mechanism to add async service that could be called in either
an async or non-async you want it to be called by anybody because sometimes like he gives an example
of uh mount uh mounting a new widget into into textual um the caller might want to care might
care about when that's actually done so they might want to wait for that but they might not they might
just like keep going because apparently textual handles it all
correctly anyway, they won't let something happen,
but the caller might not care about when it's done.
So to be able to allow both async and non-async callers to call an async
method, that's a little bit yuckier code, but he provides it.
So there's, there's a, this class, this await mount option.
So there's, I'm not going to walk through all this code,
but basically there's a way to do it.
And Will has it, has the method to allow you to have.
And I think that's kind of neat to be able to provide services
and APIs that can be called both in async and non-async ways.
Now, hopefully this still is kind of ugly.
So hopefully, as a community, we can come up with a little bit cleaner solution, but
at least there's a solution.
So it's kind of nice.
Yeah, Will did a nice job of this.
And I think it's really a huge benefit that Textual has the ability to be async, but doesn't
force you to be async.
Because if you're already writing async code, you would like it to be because it's a benefit. You can do more in parallel,
be more responsive. But if it means I have to take my non-async code and now convert the whole thing
to know about some of the parts of it being async, well, that's a hassle. And I think one of the
things that drives me nuts about Python's async, there's a few, few little things that just make me crazy about it.
It's like, wow, it's, it's so close to awesome. Right. And much of it is awesome. But for example,
if I have, if I'm in a function and I want to say, here's some async code, I want to just run it
here. So for example, async IO, you know, get, get event loop, loop.run sort of thing, or just
async IO.run to complete. If it's already being called within an async function
with some other event loop,
and you don't know about it,
under certain times it'll crash and say,
there's already an event loop,
or there is no event loop.
You're like, well, give me,
just if I don't have one, give me one.
If there is one, just give me that.
I don't care.
I just need to run something async.
And there's always this like weird,
I'm not really sure what state I am. And i get it wrong then it gives me a it crashes and
that's like ah um so i think that makes it challenging to kind of go this part we're just
going to like isolate off the async um which it sounds like will did here which is cool so that's
really excellent yeah um really quickly here too i've've had a couple of shots at this myself as well.
Nothing like published really very much
in terms of what Will's doing
or what Simon talked about.
But like, for example, on fast API chameleon
and the Jinja equivalent,
like let's just put a decorator
on top of a fast API function
and then it returns the HTML view of that and stuff. But those fast API functions,
they can be synchronous or they can be asynchronous. And so what it has to do is it has to say,
is this function a coroutine? Okay. The decorator has to return also an async one. Otherwise,
when you say async and it becomes not async, that's wrong. But if it's a sync one, you can't
return the async, right? So you you got to juggle this a lot,
which is kind of a pain.
And then the other one, I created this thing,
which I put up just as a gist
that like just lets you say this async function,
we're going to run it in a way
that won't have a conflicting event loop complaint
by constantly managing the background thread
and just pushing the work over there
and pulling the results back.
So yeah, it's interesting.
But yeah, that's a cool article.
Yeah.
Do you remember the Call Me Maybe song?
Call Me Maybe.
Yeah, I do.
Yeah.
A Wait Me Maybe.
So Chris May added, hey, I just defined you and this may be a sink, but here's my variable,
Wait Me Maybe.
Nice.
Well done, Chris.
Well done.
I love it. I love it. Well, I don't have any extras brian you got any i do um we'll try to make them quick though so uh pipey has a blog now oh let's uh pop
over to here pipey has a blog now so anyway go check it out there's not much there's a welcome
article uh so that's nice uh neat uh and And then, okay. So another extra, apparently a Docker. No,
they're laying off plans of charging people for the free team plan, which is kind of a bummer
for people like me that paid for it anyway. But anyway, so that's cool. Maybe I won't have to pay
next year. I guess they're offering refunds or something, but I'll look into it.
I guess there must have been a big backlash.
I haven't been tracking this, but.
Oh, yeah.
I mean, like, it's been a scramble all over the place of people because there's sometimes
it's a very minimal interaction with it.
And then suddenly we have to pay for it and you got to figure out how many users and how
many seats and all that sort of stuff.
And yeah.
Or if you want to use it without, so if you,
if you want to use it without the user interface, you can use it for free.
But if you like people asking are, are you using it? Yes,
we are. Cause we debug with it and everything. Um, so, uh,
so I'm glad they're backing off. Uh, I still want to, I mean,
of course it's a great service. Uh, they should be able to make money somehow.
Uh, but, um, there should be, so it's good news. Uh, should be able to make money somehow, but there should be.
So it's good news.
The only thing left I have is a joke.
Do you want to do mine first or yours first?
Let's hear yours first.
Let's go.
It's just sort of,
I was looking up some documentation
for PyTestCov
and noticed at the bottom,
so it provides a, there's mark,
there's, it provides a no cover marker,
which is nice.
So you can say, don't cover this test.
And then there's a fixture.
You can also use that as a fixture,
but then there's also the no cover fixture,
but there's a cov fixture,
which, why would you use that?
Well, it says for reasons that no one can remember,
there is a cov fixture that provides access to the underlying coverage in an instance.
Some say this is disguised as a foot gun and should be removed.
And some think mysteries make life more interesting and it should be left alone.
I love finding stuff like that in documentation.
Some think mysteries make life more interesting.
Indeed.
Indeed they do.
Okay. Fantastic. All right. I got a quick life more interesting. Indeed. Indeed they do. Okay.
Fantastic. All right. I got a quick one for you as well. This one, you knew an XKCD was coming.
Good reference earlier. So this has to do with like some deep thinking into how to make your code last so long that it becomes legacy code and people can use it for a long time and maybe
even curse its name a little bit. So there's two parallel universes here. On one, this woman just wrote this code. It took some
extra work to build, but now we're able to use it for all of our future projects. And the caption
for that is how to ensure your code is never used. The other alternate world is, let's not overthink it. If this code is still in use
that far in the future, it will have bigger problems. How to ensure that your code lives
forever? And the hover is surely no one, everyone will recognize how flexible and useful this
architecture is. Spend a huge amount of effort painstakingly preserving and updating this
garbage I wrote in 20 minutes. Yeah. Well, mean it's there's so many examples of that isn't there i mean oh yeah
ah yeah i mean internally there's tons there's like oh just this throw this thing together
build script or whatever and it's just we'll rewrite it later 10 years later we haven't
rewritten it um things like that um I mean, flask was like a really
quick hack, wasn't it? Like a joke at first or something? I think it was an April Fool's thing.
I think so. Anyway, and the other side is the lesson that I think people should learn is
planning on reuse is just a mistake. And I've been in many, many design meetings where it's like, let's not plan six years out into the future on this.
That's ridiculous.
We don't even know.
Because I've also seen people plan for it, and it is reused, and it is maintained.
But the things that you thought you were going to need to be variable are not the things that really need to change in the future.
It's something else.
Yeah. Somewhere in the middle there lives
a, let's not overthink this, get it out there.
Oh, let's take a moment and refactor it
so it's more reasonable in the way we
now know it needs to be. Carry on.
So my advice,
keep the interface simple, keep it minimal,
document it, and test it.
And then if it grows, great.
Yep. Excellent excellent thanks for that
that's funny yeah for sure and thanks everybody for showing up and thanks michael again for
yeah great to be here