Python Bytes - #195 Runtime type checking for Python type hints
Episode Date: August 18, 2020Topics covered in this episode: watchdog Status code 418 pydantic’s new Validation decorator Building Python Extension Modules in Assembly easy property Non Blocking Assertion Failures with pytes...t-check Extras Joke See the full show notes for this episode on the website at pythonbytes.fm/195
Transcript
Discussion (0)
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
This is episode 195, recorded August 12th, 2020.
I'm Michael Kennedy.
And I am Brian Harkin.
And this episode is brought to you by all the cool work that we're doing.
Tell you more about this.
Right now, I kind of just want to think about paying attention to stuff, Brian.
Maybe watching things.
Oh, like look closer.
Yes, like watch carefully.
So actually, this thing sent over by Preysen Daniel,
he sends us a bunch of good topics and links.
And this one's called Watchdog.
And maybe you've heard of it.
It's the foundation of some web frameworks, for example,
and things like that to know if, say, a file has changed that you're editing.
Does it need to auto-restart the website?
So when you refresh it, it actually reruns it,
things like that.
But Watchdog is a cool little library
that you can use just on your own
to know if something has changed.
So basically it's a simple little API.
You create this thing called an observer
and you tell it to just start watching in some way.
You give it a path.
It can recursively look,
you can give it like a pattern or whatnot.
And it will say,
just basically start firing events back on this observer thing.
When stuff happens,
files created,
files deleted,
files modified and so on.
Nice.
This is cool.
Yeah.
Isn't that cool?
It also comes with a CLI script called Watch Me Do.
And what you can do with Watch Me Do is just type Watch Me Do, all one word, log.
And wherever your current working directory is when you type that, it will just start watching for files that change right there, just like on the command line.
Oh, okay, cool.
So if you're, you know, you don't want to write a program, but you just happen to be somewhere and you're like,
what is happening?
Like what files are being modified or being touched or being changed here?
And you can just type that and boom, there it goes.
That's cool, right?
That actually is really cool.
Yeah.
We have a build process that part of it is mucking up some directories
and it'd be kind of cool to use something like this.
Yeah, absolutely.
And so you could just pip install watchdog
and then just type
watch me do space log wherever you wanted to know there's a bunch of other things it does that you
can pass commands and stuff i suppose like you could ask it to recursively watch or whatever but
yeah i haven't had a use case for that so but yeah this is a cool recommendation from prasen
yeah nice the example that i think I could possibly use it for is,
one of the things that we do that makes Pythonbytes.fm,
as well as all the TalkPython, TalkPython training sites,
ridiculously fast as a user,
is we don't require you to re-download almost any of the static content.
Anything JavaScript, any image in the entire site,
you know,
CSS,
all of those things,
they're cached for a year.
Right.
And so a problem with caching stuff for a long time is if you redeploy a new
version,
something's wacky,
right?
Something is really weird.
Like I have this problem with Twitter and Firefox.
I'll go there and periodically it'll just say something went wrong.
Can't load it.
And a command R, a hard refresh always fixes it because there's probably some JavaScript file
that's like out of sync with some other part of some API or some random thing like that.
And so what we do to make sure that never happens is we look at every one of those static files that
we have a year long cache on and we read it and we create the hash and we put question mark hash equals the hash of the file on the end of it. So that, you know,
that's a separate file that ever changes one character of it changes, the hash changes,
and it's now a totally separate thing in the web browser cache, right? Although this is perfect,
the one drawback is to make things fast, you're not rehashing all the images on every request.
It just says, have I seen this file before?
Do I already compute the hash?
Just use it.
So that's fine, but that means that little hash refresh trick only really works
if I restart the website.
If, say, only a CSS file changed.
I could use this watchdog to watch all the static files that were hashing.
If any of them change, just instantly
recompute the hash. That's it.
So that would allow me to do push
deploys of just
static content changes without
kicking the website at all. And it would
just magically redetect those
and start rolling. I think I might start using
watchdog for that. Anyway, that's my use
case that makes me excited. And I'm glad you pronounced watch me do because I looked at it
and I went watch meadow. That's a weird name. That is a way I think it's watching me do.
Watch me do is better. Yeah. You know what else is weird? Weird HTTP status codes. Like I'm very
familiar with 400 bad requests. That's when somebody's created an API and I talk to it badly
and they've created the API correctly.
Or I get a 500 where their stuff has crashed
because I sent them something bad and they've written their API badly.
But somewhere in between there lives some odd thing, right?
Yes.
Have you heard of error code 418 before?
I'm a teapot.
This is just great.
I love it.
I love it.
Status code 418.
I'm a teapot.
Any attempt to brew a coffee with a teapot should result in an error code 418.
I'm a teapot.
The resulting entity may be short and stout.
The resulting entity may be short and stout.
I love it.
This actually got brought up in a conversation
I was having this morning.
A colleague of mine, Andy Howe, suggested it.
He said, so when is Python 3.9 going to come out?
Because hasn't it been a while?
And as a reminder to everybody,
Python 3.9, the release candidate one,
or RCCR, whatever out now so you can play
with it it's probably I've been using it it's safe to use but the uh the schedule for the release
final release is in October I believe and then after that bug fixes releases every two months
are planned if there are any Andy he said you know my favorite enhancement
for python 3.9 is this uh 4.18 i'm a teapot this is new in python 3.9 http library was missing the
status code 4.18 i'm a teapot and and now it has it in there wow, I've got some links for you because in the show notes, this is referenced from HTCPCP, which is Hypertext Coffee Pot Control Protocol.
And this came out in 1998 as an April Fool's joke.
And then it's kind of part of it now.
So it's part of HTTP, sort of.
Another fun error code so ht the document the entire document
for http says that most error codes share the same status codes as http however uh 418 is separate
but also now http can use that also but also for except 406 not acceptable. So 406 is
this response code may
be returned if the operator of the coffee pot
cannot comply with the accept
addition request unless the request
was in ahead.
And it should return
the list of possible coffee
additions. This is bizarre that this
is in the world.
This is awesome. I really love it. I
didn't realize it had been taken so far as this. This is great. And if you go and look at the thing
you linked to, the hypertext coffee pot control protocol, HTC PCP slash 1.0, the whole memo
describes so much of this thing. And it even talks about things like crossing firewalls
like modern coffee pots do not use fire however a firewall is useful in protecting it
it also addresses the security considerations anyone who gets between me and my morning coffee
should be insecure unmoderated access to unprotected coffee pots from internet users
might lead to several kinds of denial of coffee service attacks.
The improper use of filtration devices
might admit Trojan grounds.
Filtration is not a good virus protection method.
I mean, it just goes on and on.
It's beautiful.
Yes.
And there's a security layer that I forgot about
that's funny too, that's part of this,
but I can't find it right now.
Yeah, no worries.
I threw in a quick link also to um this place called htpstatuses.com which this is a slightly
more serious take although it does of course include the coffee pot but it's just if you were
like what the heck should i be doing you know in this situation like here's the error codes here so
on if you just click on them it gives you like a really nice summary like if you click on 403 for example it talks about
when it's used and when it's like how it compares to 404 and then also how that reference code is
set up as an enumeration in different languages so for example in go it's http.status forbidden
in rails it's colon forbidden and in Python 3 it's
http.hppstatus.forbidden
and things like that so it tells you like the
the language version
instead of typing it all in yourself
and having magic strings and numbers everywhere
yeah so it does look like
I don't know what symphony is but
both symphony and Go
do also support 418
status team beautiful we're on par with Go in terms of the internet now Both Symfony and Go do also support 4.1.8 status.
Beautiful.
We're on par with Go in terms of the internet now.
Very good.
That was a good one.
It almost could have been the joke, but I like it. All right.
Also, things that I like is that we get a chance to create amazing stuff to help people get better with Python out there.
So over at TalkPython Training, we have three new courses coming very soon.
We have Getting Started with Data Science.
We have Moving from Excel to Python.
And we have Diving into Python Memory Management and Optimizing Your Programs around that.
All three of those are coming within probably a month or so.
So if you want to get notified about that, just visit training.talkpython.fm.
And right at the front, there's a little email place you can enter your email address to get notified.
How about you?
I wanted to highlight Test & Code.
So PyTest 6 is out.
So Test & Code is the other podcast I do at testandcode.com.
And I had talked last week that there was going to be a PyTest 6 episode.
And instead of doing it just by myself, I contacted Anthony Sotili
and had him come on the show.
And so we BS about stuff for about an hour, some of its actual content.
So I'm really trying to get, I'd really like to have the shorter episodes on there,
but, you know, I get talking to somebody and it's just fun.
Just keeps going.
Awesome.
Yeah, it's definitely a good one.
People should check it out.
What do we got next?
We talked about Pydantic, right?
So Pydantic is a cool library.
It's something I really just need to start using.
I haven't created any new projects that probably really deserve this,
but I think it's definitely one of those things that I want to start using
because it's just so slick.
The ability to say, I have these models, they have these types, you can validate them, you can auto convert between them and so on.
So we talked about that not too long ago, actually.
However, Andy Shapiro sent over a heads up about a new feature that's in the beta version of Pydantic that's coming.
That makes me pretty excited actually I
don't know we'll see how people feel about this but I'm excited about it I'm excited because I'm
a fan of type hints yeah me too I love type hints yeah I love them mostly because the way they make
the editor help me write code instead of going and saying oh how do I do this thing with this
library right if I just say the type of this thing is one of the objects out of that library and I hit dot, boom.
The editor shows me all the stuff I can do.
It just keeps me in flow and working on what I need to.
So I love type hints mostly for that, but also for the validation.
One of the things they are like, but they do not do, is they are not like static typing in other programming languages where somehow that verifies what's being passed, right?
Yeah.
So, like, for example, if I have a function, it says it takes an integer, an age colon int, and that's what it says it takes.
But then I go and I write code and I give it quote seven instead of the number seven.
That's fine.
Python's like, yeah, that's cool.
You probably don't know what you're doing, but whatever. We're just going to let it
fly. Right? Well, with Pydantic, there's this new type annotation validator. And so what you can do
is you can say for this function, it has type annotations and I want those to mean something.
Okay. So it gives it basically that it's not runtime behavior in the static languages. It's a compile error, right?
Your argument string cannot be converted to enter whatever the compilation error happens to be.
But it would give you the runtime equivalent.
So all you have to do is you have a regular Python function and it has regular types,
just like it would, you know, s colon str count colon int, that type of thing.
And you can just work with it. It's a little bit
smarter than the compiler, maybe of say, like C++ or C sharp, though, in that what you do is you
just say at validate arguments, you give it a decorator that validates the arguments. And not
only does it validate, but it will convert if it can. So for example, I'll put an example in our
show notes, there's a function called repeat, it takes a string and a number. And it's just gonna echo out that string, however
many times that number exists, right? So you can say repeat, quote, hello, comma three, and it'll
print hello three times. Super simple. That passes the validation precisely because it takes a string
and an integer. But you can also say repeat hello, quote for,
and it'll still print out hello four times
because it can take the string for and make it an integer for.
Oh, that's cool.
Right?
But if I say repeat hello, goodbye, boom, exception, validation error,
you know, the value is not a valid integer,
type equals type error integer or whatever
like some message there right so it says the count parameter is not and cannot be converted to
the type specified by the type annotation oh yeah this is cool how do you feel about this i would
obviously don't want a runtime typing for all of python code it's not I don't want it. But for special places, like maybe around your API?
Exactly.
The boundary of libraries, like stuff going in there.
Yeah.
You're like, please don't send me the wrong data.
What is your other alternative, right?
If you really want to validate that, you have to do is instance of an end
or try to cast it to an end.
And then you've got to raise your own exception
type and all that kind of you're already going to have to do that work if you're writing a good api
or you're going to send out weird errors like int does not have you know type int does not have
function split or some weird thing and people have to realize like oh what that means is
you type some kind of you send a number
where a string value is accepted right so this yeah if you really do depend on the types that
you specify in your type annotation this seems like a good idea to me the one drawback is this
cannot make your code faster right if it's doing both validation and type conversion yeah in front
of your code it can't be faster than just not doing that.
But it might make your development faster.
It's not always about speed.
Exactly, and may make your sanity.
Yeah, so one of the ways people have gotten around this
in the past is instead of,
like for an example,
doing instead of trying to validate parameters
to function at an API level,
have the parameters bundled into like a
an adders object and have
adders validators written
because adders does a... Right, right.
Put it into a validated object
type and then pass that thing over. Yeah.
Gotcha. Which is kind of what this is.
Yeah. But without doing it. This is cool.
Yeah. I like it. Yeah, very cool. I like it
too. I was leaning pidentically previously. This makes me lean more that way. I like it. All right. So one of the
things that's really cool is, you know, we've had a lot of conversations about is Python fast? Is it
slow? Is it fast for coming up with programs that work? Does it execute fast? Should you use
libraries like Cython or rewrite some stuff in Rust, but Anthony Shaw, he took it to another level,
like further down than even something like rewrite bits in C
or compile Python to C or something.
Yeah, I think this is maybe an example of Anthony
just having too much time on his hands, I think, maybe.
So Anthony wrote a, I just tried it this morning,
a project called PyMult, P-Y-M-U-L-T.
You can pip install it, and it just multiplies numbers,
and it only works for positive integers or negative integers.
It just doesn't do, it doesn't ever display negative numbers.
Anyway, regardless of that,
it's an extension for Python written in assembly.
Because why not?
And because of Anthony.
As in like MV and your ad, like the assembly language,
that's the foundation of basically every other programming language?
Yeah.
In Anthony's Twitter announcement, he says,
after a series of highly questionable life decisions,
my Python extension written in pure assembly is now on PyPI.
It required an assembly extension for disk utils.
He also wrote a GitHub action support, so it's running
CICD and testing with PyTest. Above and beyond, over the top.
But there is some coolness of it, so it's a proof of concept to demonstrate
how to create a Python extension in 100% assembly.
And then how to link those up,
how to call a CA API and create a PyObject
and parse PyTubel and stuff like that.
Basically all the stuff you have to do
to get point parameters back
and values out of an extension written in assembly.
And yeah, it's interesting.
So I like it, actually.
Yeah.
And anyone wants to know what the code looks like, it's like move racks, x, i, mol, q,
word of y, move result to racks, move eddy to result.
Like it's, yeah.
But then you get a call pylon from long which
is kind of a cool thing so there's this like interesting mix between the just pure assembly
language and the c data types of c python on a serious note though anybody wanting to learn a
little bit of assembly or something it's not like often you need some sort of environment to try it out in. Having some way to link Python and assembly is kind of neat, actually.
So I'm grateful for that.
You're right.
Some of these commands.
I mean, I wrote some assembly in college.
That was a long time ago.
Yeah.
Well, you had tipped Anthony because that's some impressive stuff.
Yep.
Would you say it's easy, though?
No.
No.
That's hard mode.
Yeah.
You know what? Actually, it's not as easy, I think, as it should be.
And it's honestly just bizarre.
Our properties in Python, as in at property, some function returns some value,
converts what looks like a function call over to something that looks like field access, right?
Yeah.
But why, oh, why does it have to have this bizarre sequence of conventions
where I have an app property and then a function that has a name?
Okay, that defines the name of the property.
That makes sense.
But then the subsequent thing, if I want to be able to set that,
I have to say if the property was A,
then I have to say decorator A.setter
and also have a function that is called A.
The A.setter stuff is weird. And then the order of the setter and also have a function that is called a like the a dot setter stuff is weird and then
the order of the setter varies as well right it has to be or is constrained it has to be after
the property a and what i've found also is that you can run into issues with inheritance i think
if the property is defined in the base class you try to create a setter on a drive class things
don't work right as well which is all kinds kinds of weird, right? So there's just
like, this is supposed to make life easy. Why is this so complicated? Like,
surely there was just another alternative that was like easier to do to implement as well.
Anyway, it's always kind of been one of the bizarro things of Python. That said, I love
properties. I love that you can do like lazy calculation with them.
You don't have to store them.
It's part of the memory.
If they can be recomputed from the values,
there's a lot of good reasons to have them.
So Ruud van der Ham sent over this cool project,
which he created called Easy Property.
And do you know what?
It's easier than regular properties.
Okay.
I think that's why he named it that.
So the idea is, you know what? It's easier than regular properties. Okay. I think that's why he named it that. So the idea is, you know what you could do?
Instead of have this property and then at a dot setter or a dot deleter is you could
just say there's a at getter, at setter, at deleter on the thing.
And it doesn't matter what order they are or if they're all defined.
Like, for example, you can't have a setter without a getter. Now, conceptually, you should never
really do that. But just, you know, syntactically, like those things have to be defined there. And
like I said, the sort of base class, derive class type of thing, it gets wonky as well.
So with this, you just create a function, the function name is the name of the property and then you put
at getter on it and that makes it the kind that is you know the getter property if you want to
have one you can set you say at setter the order doesn't matter or anything like that nice isn't
that nice yeah so there's a um a cool little example that he wrote you know you can do them
separately which is probably what I would recommend and do,
but you can also have an at getter setter. So you can have one function whose job is to both
be the getter and the setter operation of the property. And then the way it works is just the
value is set to be like some default value, which is what happens in the get version.
You can have an add documenter.
You can have an add documenter.
So you can also have documentation for your property.
And there's a little function that will come up and do that.
So anyway, it looks pretty nice to me.
It's not one of those things that's going to be,
you're taking a heavy dependency upon to give it a try, right?
It's not like a runtime thing.
For example, that validate arguments,
that's in between every time you call
a function all the time, all the time, right?
So this is the type of thing, if it's going to work,
it's going to work clearly, or it's just not going to work
at all. So give it a try and see if it makes you
happy, and if it sparks
joy, you can have an at getter.
And I like the syntax better than properties.
Just more sense. Yeah, and you know, I think at property is just fine. Like, okay, that totally worksjoy you can have an at getter and i like the syntax better than properties just yeah yeah and
you know i think at property is just fine like okay that totally but you know at property name
dot setter like that just drives me it's just so bizarre and weird in the ordering and the
dependencies of it existing in the same class hierarchy level yeah don't get me started so
this is cool i like it Thanks for developing that and sending that
over, Rude. So we talked about
assembly and properties
and decorators and stuff. So if anybody's
left listening to this podcast,
we do have more
to talk about. Let's talk about recursion. No,
just kidding. I couldn't
resist highlighting the last topic.
So there was an article by
Ryan Howard that was on the testproject.io blog
called Non-Blocking Assertion Failures with PyTestCheck.
And I had to highlight it
because it's really the first time
anybody's ever written an article
about something I wrote.
So that's neat.
So PyTestCheck is a library
that allows you to do multiple failures within a test,
mostly because assert, normally you use Asserts,
but Asserts stop after the first failure,
and sometimes you want more.
And I never really thought about the different use cases,
but so Orion has the use case of using it with Selenium
because sometimes when you're testing a page coming back,
you might have to test multiple aspects of it.
His example was what's the his example was
uh what's the content of some field and also uh if the url is correct or something and i think
with like a selenium or some sort of web test that totally makes sense because you'd have things like
you want to check the error code and content and whether somebody's name shows up, then a whole bunch of stuff you could check
and having multiple things.
Right.
You don't necessarily have just one assertion
that captures all of the essence
of what you're trying to determine, right?
Yeah.
And so I also link to the PyTest check library
or plugin,
and then also an article that I wrote way and way back in 2015 where i started thinking
about this and thinking how to solve it so okay yeah yeah very cool nice article right and then
uh i also wanted to um do a public service announcement that because both ryan and anthony
got this wrong there are no capital letters in pytest so hold on hold on let me try this let me
just yeah okay on this one but if I go over to Word
and I type PyTest is a testing framework,
I'll bet you that Word makes it capital.
Doesn't that make it real?
No.
I know PowerPoint well.
No, yeah, that's always tricky, right?
When you have sort of a formal name,
but the formal name doesn't have spaces or it's lowercase,
but i'm
fine with it we got used to it with iphone so there's no capital i mean the p is capitalized
in iphone but yeah what will word uh correct you i wonder if you try to type iphone i would doubt
it i mean but that's apple and they think differently that's what they tell me but there's
others i mean so there's some i guess it it's a weird thing with tools and stuff.
Some tools don't care whether you like,
whether you capitalize or not.
The people in PyTest like it,
not capitalize.
So anyway.
Yeah.
Let's,
let's respect their lowercase P's.
Yeah.
All right.
So I have three really quick things.
They're all kind of fun. So PyMC is a cool library for Bayesian analysis
and probabilistic programming in Python.
So Alex, one of the core developers there,
sent me a message, said,
hey, we're planning the first ever PyMC on.
Okay.
Pronounce PyMC on because it's so on, they say.
And it's the first bayesian community
online conference around py mc so if you are into probabilistic programming of python
check it out there's a bunch of um cool stuff they got going on they're also i think
have a call for paper so if you want to do a prison presentations if you want to do a
presentation shoot them a note.
And yeah, I'll link to that in the show notes.
Second, a while ago, we talked about Rumps.
Quite a while ago.
Rumps is ridiculously uncomplicated Mac, I don't know, something.
Menu programs or something like that.
And so I ended up, I was sitting around.
I have this little library that I run because so many things in my life require taking a title or taking some words and turning them into a file name or a
URL name. All right. So suppose I've got the title of a video and I want to name an MP4 file that,
and it's got like a colon in it or like a forward slash or some random thing that
shouldn't be in there i don't want spaces i want so i wrote this little command line utility called
urlify that i would just run it would take whatever's in the clipboard and replace it with
that canonicalized version that would work well as a file name oh cool yeah that was cool but then
i got tired of like always firing up the command line, the terminal, maybe it's busy doing something else. So I got to do a new window, run that thing and then close it
down. And I was like, I just want to click something once, right? I don't want to click
the terminal and then start a new terminal. And it was like, not that much work, but you can imagine
the way I'm going on and on about this. I must be doing it more than is reasonable.
So what I did is in like 45 minutes,
I converted that command line app
to a Mac.app file,
like a full on.app file
that I could just ship to any Mac user.
They have no idea.
It uses multiple Python packages,
a code that I wrote,
and it runs as a GUI auto-starting
with my Mac OS when I log in in my menu bar.
Is that cool?
Yeah.
And so I linked to a little tweet that has a screenshot just says convert text,
but actually I changed it to URL-fy text, trim text,
and now I can just click up there and any text that I have, you know,
if you copy something and you want to like paste an email or like,
but maybe it's got a bunch of white space, you're like, why is this all here?
Instead of putting it in text editor and just getting the little bit out,
I just hit that and it'll trim it
or like a good lowercase text.
So like have these like little cool
like clipboard text transforms.
And it all took like 45 minutes
to turn it into a Mac app
with Pi to app and rumps.
Oh, wow.
So are you sharing this somewhere?
I will happily share it.
Okay.
But I don't have the GitHub repo public yet.
So let me just like put like a screenshot
and what the heck it is and then I can make it public.
But yeah, so I'll put it in the show notes.
Neat.
Yeah, yeah, it's super cool.
And finally, I just want to let people know
who are taking courses over at TalkPython.
I was sitting around and I decided I want,
as you hover over the scrubber,
I want it to show a little thumbnail of where
you would go in the video if you were to click the scrubber in that location that's a scrub we're not
like the little like time thing where you can click around and like zoom ahead and whatever
and we're not like reusing vimeo or youtube or something that might potentially do that i think
youtube does it i don't know that vimeo does anyway i recently figured out how to do that. I think YouTube does it. I don't know that Vimeo does. Anyway, I recently figured out how to do that.
So if people are interested, they can check it out.
But there's a cool little trick
where you can take a second hidden video player
and point it at either the same video
or a smaller version of the video.
And then as the mouse moves,
just seek it to that time and show it above
where the mouse is isn't that crazy yeah that's yeah so if people need something like that yeah
a little cool trick you might consider not not that often in python but if you happen to make
your way to the javascript side of things you'll do a lot of that i guess so is that in your
for your training site has it been updated exactly. It's not updated as we speak because I'm still busy transcoding 200 hours of video
to 500 by 200 size.
So I'm about halfway through that.
Yesterday, I uploaded 200 gigs of data.
I'm so going over my data limit this month.
That was 20% of my data limit in one day.
I got more to send.
So, but yeah, it'll be there as soon as the videos are done.
It'll turn it on.
I'm going to back up a little bit.
This IMC, probabilistic programming.
Can I use this to make a probability drive?
A probability drive?
Yeah.
Is this from science fiction?
I don't know it.
Like Hitchhiker's Guide to the Galaxy.
Oh, yeah, I would think so.
I would begin by feeding it the number 42 and see what comes out.
Maybe, yeah.
That's probably the natural first step, yeah.
All right, speaking of jokes, we've got two.
You want to go first?
Yes.
This was submitted by Reuven Lerner, inspired by Anthony Shaw.
I used to do low-level programming.
Then a product I bought told me no assembly required.
Since then, I've been coding in Python.
Nice.
Except for Anthony.
Anthony's coding in assembly.
He codes in both, yeah.
His Python is assembly code or something like that.
So this one, like last week, we talked about little Bobby Tables,
who's beautiful, over at XKCD.
And I've got another XKCD for us.
But this one is not about databases.
No, it's about source control and Git.
Okay.
All right.
You want to be the woman developer
that asks the question?
I'll start us off.
All right.
So there's a couple developers speaking.
First one is talking about this new source control.
This is Git.
It tracks collaborative work on projects
through a beautiful distributed graph theory tree model. Cool. How do we
use it? No idea. Just memorize these shell
commands and type them to sync up. If you get errors,
save your work elsewhere, delete the
project, and download a fresh copy.
It's funny because it happens
too often, I think.
Yeah. I think most people have
the four or five or six git commands
that they use all the time and everything else they have to look up.
Yeah.
Merge conflict.
All right, I'm deleting it.
I'm going to copy this back over.
Yep.
All right.
Funny indeed.
Well, thanks for being here as always and thanks everyone for listening.
Thank you.
Bye.
Yep, bye.
Thank you for listening to Python Bytes.
Follow the show on Twitter via 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.
On behalf of myself and Brian Ocken, this is Michael Kennedy.
Thank you for listening and sharing this podcast with your friends and colleagues.