It's been said that JavaScript is the assembly language of the web,
but should you be required to write an assembly language or even JavaScript if you don't want to?
Most platforms have a dizzying array of options for programming them.
Not the front-end web world, but that tide may be turning,
and WebAssembly could be the key to making it happen.
With WebAssembly, we have a new compilation target for web browsers,
and Michael Dropboom from Mozilla and his team have decided to help bring
the Python scientific stack to the front-end world with Pyodide.
Dive into Pyodide on this episode, 212, of Talk Python to Me, recorded April 23, 2019.
Welcome to Talk Python to Me, a weekly podcast on Python,
the language, the libraries, the ecosystem, and the personalities.
This is your host, Michael Kennedy.
Follow me on Twitter, where I'm @mkennedy.
Keep up with the show and listen to past episodes at talkpython.fm,
and follow the show on Twitter via at Talk Python.
This episode is brought to you by Microsoft.
Be sure to check out what they're offering during their segments.
It really helps support the show.
Michael, welcome to Talk Python.
Thanks. It's good to be here. Thanks for inviting me.
Oh, you have such an interesting topic and thing that you've been working on.
I was really excited when I heard about Pyodide a little bit, I don't know, maybe six months ago
or when I first heard about it and stuff.
And I was like, oh, this has some real possibilities.
So I'm really excited to have you here to dig into that.
Cool.
Yeah.
Now, before we do get into that, let's start at the beginning.
Let's start with your story.
How did you get into programming in Python?
So I've been programming almost as long as I can remember.
I think my parents brought home like an IBM XT sometime in the mid-80s.
And I learned, you know, basic on that as one does.
And just have been programming ever since.
I found Python, I think, in 1996 while I was at university.
And I sort of used it secretly in the background to like prototype my assignments that I had to
write in other languages.
I would kind of write these quick little hacks as I'm learning to program in Python because it
was a lot easier for me.
And then once I had figured out the problem, I'll convert it to LIS.
I can now solve the syntax problem to make this happen over here, right?
Exactly.
Yeah.
What languages were you using?
There was a lot of LIS where I went to school and as well as Java and ML was a big thing then,
which, you know, sort of grew into Hamill and that family of languages.
Yeah.
My first CS language that I only took a couple of CS classes as a minor type of thing,
but my first one was in Scheme, which is a derivative of LISP, right?
And I felt that it was both very mind shifting and very interesting and also super not useful.
Like what was your feeling of studying LISP early on?
Like I can't go build anything with this.
What is this crazy language?
Yeah, it definitely is kind of mind bending.
And, you know, I think it enforces a lot of good habits, like functional programming ideas
that you can bring into any language that are probably good habits to have.
But yeah, like you say, it's not always the most practical.
I know this is a question that usually is at the end of your show, but I use Emacs.
And so occasionally to write Emacs extensions, I'll bring out LISP.
And what's fascinating about it is Emacs is basically built by monkey patching everything else.
That's Emacs extensions, basically monkey patching is the functional thing that you do,
which I find interesting.
That is interesting.
Wow.
I guess tends to happen in LISP a lot.
Well, that's the only big LISP code I'm really familiar with.
Yeah, Emacs is definitely one of the bigger projects.
Quite, quite interesting.
Cool.
Okay, so you sort of used it.
You got into it pretty early, right?
Like, what is that?
Four or five years into the existence of Python, which for Python, you know, it grew grassroots.
It wasn't like busted on the scene by Microsoft or Apple or whoever, right?
That's pretty early.
Yeah, I went to my first Python conference in 2001.
And at that point, I don't remember the exact number, but I would guess it was maybe around
200 people, not much larger than that.
It was one track.
Everybody could fit in one room.
It was small enough that as a grad student, I was able to just walk up to Guido and have
a talk with him because there wasn't that many people demanding his attention.
And of course, now you go to PyCon and, you know, forget anything like that happening.
There's just thousands of people.
And yeah, it's completely crazy.
Yeah.
I mean, it's really fun to see how big the community has grown.
On the other hand, I do miss the days of the sort of smaller conferences where you feel
like you got a hold of it and you feel like you got a sense of seeing a lot of the stuff.
But yeah, these are good problems to have, I guess.
I guess they are.
How does it feel to do Python now versus then?
It's got to be kind of different with pip install, anti-gravity and all that.
Yeah, I think definitely having good package management means you're no longer compelled
to like bring everything into your projects in the same way.
So I used to be the developer on Matplotlib.
And one of its sort of, I guess, technical debt, for lack of a better word, is the fact
that for the longest time it was if someone had a great idea for a new plot type, we'd just
say, yeah, let's include it in Matplotlib.
Because the alternative was forcing all the users to install a bunch of packages, which
was really hard at the time.
So we would make this one really big package.
And, you know, in hindsight, that's not the greatest thing.
It means a lot of code for the core developers of that project to maintain.
So it is nice that we live in this world now where we can have lots of little packages that
interact.
And that's not a huge burden on the user as it once was.
Yeah, that's pretty interesting.
I mean, maybe it would have been better to have a bunch of little Matplotlib dash extensions
that you include in your requirements files if you want to do these kind of graphs and stuff.
And you could have kept it a little more distributed in terms of support.
But yeah, it's the right architecture and patterns for the right time, right?
And that's what you needed, yeah?
Yeah.
Cool.
So you both work at a cool web company and do data science.
So you kind of do both of the things that Python is really good at simultaneously, right?
Tell us about that.
Yeah, so I'm a data engineer at Mozilla.
I've been there about a year and a half.
And I work on the team that manages the telemetry that comes from our products.
So from Firefox on desktop and on Android and iOS and all these things.
You know, and the telemetry goes into improving the product.
It helps us discover when things are going wrong, whether things are getting better with changes
or worse with changes and things like that.
And so there's a whole team that manages collecting that data, ingesting that data, and then providing
ways for people to analyze it at the end of the day.
And what's really exciting about how they do that at Mozilla is we have this document called
our Lean Data Practices, where we try really hard to not collect anything that we don't
need to collect, not collect anything that will invade people's privacy.
We really are just collecting what we need in order to improve the product.
And so it's really nice to come at it from that point of view, not just to sort of snarf
it all up and see what we can do later, but to really think upfront, do we need to do this
and do we need to collect this?
Yeah, that's super cool.
Like maybe you had for a while, Firefox had the address bar and then like a search box,
right?
Most of the browsers have given up on this idea.
But you could tell that from telemetry, right?
How people are using each part and so on, yeah?
Exactly.
Yeah.
We're able to sort of see how the search bar is getting used even now that it's a unified
thing.
It's a really fun place to work.
The engineering talent there is just beyond anything I've ever had the privilege of working
with.
So I can imagine that it's super awesome.
I'm personally a big fan of Firefox.
I generally just use Firefox if at all possible.
And it frustrates me to no end where I go to places and they're like, this page is only
available on Chrome or this site only streams this video on Safari.
And you know there's no good reason for it other than they're just lazy to do like the
tiny bit of effort to make it work, right?
Yeah.
It's unfortunate.
You know, I think one of Firefox's biggest challenges is that unfortunately there's like
a network or a snowball effect, right?
It's that the more websites that don't work on Firefox, the fewer people are going to use
it.
And therefore, the fewer websites are going to work on Firefox.
And so trying to break out of that cycle is sort of a constant battle for us that we're
tackling on a number of fronts.
Props to you guys.
You're doing great stuff, keeping the web open.
I really am a big fan of Mozilla.
And I guess our topic today is just one more reason why.
Cool.
Yeah, absolutely.
So we're going to talk about WebAssembly and Pyodide.
But I think it maybe makes sense to just sort of lay out a little bit of the history of like
what even led to WebAs, not necessarily what led to WebAssembly, but like what preceded WebAssembly,
you know?
Sure.
Maybe I'll take it up to WebAssembly and you can take it from there.
So we have way back in, I don't know, 1995, browsers were things that looked at documents
and people imagine like what if they could do more than just show documents, right?
So Netscape, that company that used to exist, I also was a fan of them.
Guys at Netscape came up with JavaScript and it was named JavaScript not because it had anything
to do Java, but because Java was cool and hot.
So this is the scripty cool language.
In 10 days, like it was created in 10 days, start to finish and shipped in Netscape Navigator,
like three months later or something.
And boom, it oddly becomes the most popular language in the world and sort of becomes like
this assembly language of the internet or maybe C, I don't know how you think about it, like
just the base language of the internet, right?
And then some other projects came along, ASM, ASM, ASM.JS, and some other ones show that you
can take C code, compile it down to JavaScript and do incredible stuff.
Like there's a super, super funny video by Gary Barnhart called The Birth and Death of JavaScript.
Have you seen this video?
Yeah, it's fantastic.
It's like 15 minutes of beautiful history, but humor all mixed together.
It's really, really insightful.
And basically in there, he shows things like, I don't remember the exact one, like Chrome
running in JavaScript inside of Firefox or the other way around, just like really interesting
stuff like C games in the browser and all that stuff is amazing.
So it really like showed the possibility of, you know, like the web really can be, and JavaScript
can be the foundation of not just jQuery and Angular, but Doom or Quake or Firefox, right?
Like incredible power.
But it doesn't make a lot of sense to compile stuff to JavaScript, to ship it down, to then
reinterpret it, to like then compile it and JIT it and run it.
Like, wouldn't it be better if there was a binary way to like compile for the web, right?
And so that's my, I guess my introduction to this idea of WebAssembly, right?
Yeah, that's a great little history.
I mean, most of that predates my coming to WebAssembly.
I've only been using WebAssembly for about a year and a half when this whole project started.
So fortunately, Mozilla has a lot of people who do work on WebAssembly and have web data from the
beginning.
So it's really nice.
Did it originate with Mozilla?
It did.
Yeah.
I felt like Rust and WebAssembly and all that stuff kind of came from you guys.
Exactly.
Yeah.
It originated at Mozilla, but it is definitely an open standard that all the browsers are supporting
and all that stuff.
Yeah.
Super cool.
So, I mean, maybe give the elevator pitch of like, what is WebAssembly for folks who don't
necessarily know?
Yeah.
So it's basically a binary format.
It's designed to be something that your compiler writes to.
It's not something you would ever write by hand or people do.
It's a target for something like a C compiler or a Fortran compiler or a Rust compiler, right?
Any of these compiled languages.
And when that gets shipped to your browser, the browser then converts that into native machine
code that runs on your machine.
But it's also running inside of the same browser sandbox that runs your JavaScript.
So it has the same sort of security space and constraints as JavaScript.
Right.
One of the concerns people have is like, well, JavaScript is safe because it's this sandbox
thing and it only has so much in the language.
If you start running arbitrary binary code, all bets are off.
But it's not just like, here's some machine instructions.
It's, oh, here's a binary thing that runs in the WebAssembly world, right?
Yeah.
So these are details I don't know too much about.
But they definitely is making all these assurances that the sort of typical things you can do
in C that become security flaws, you cannot do in WebAssembly.
Or if you do them, you don't break out of the browser, right?
Right.
You just get an exception or something, right?
Exactly.
Yeah.
Cool.
Dan Callahan, another Mozilla person, gave a pretty interesting call to action around WebAssembly
last year in one of the PyCon keynotes at US PyCon.
Were you there for that?
I wasn't there.
And actually, what's interesting about that is I had already been working on PyDyde for
a few months when he gave that talk.
And he and I were not aware of each other at all.
It just sort of explains how big a place Mozilla is.
Yeah, yeah, yeah.
For sure.
You know, nobody's fault at either end at all.
And you guys also have like PyPyJS, which I don't think is active anymore.
But there's like a lot of these little flowers blooming in that world, right?
Exactly.
And so it was really cool to see his talk and sort of realize we were thinking along the
same lines.
And we sort of check in with each other periodically on what's going on there, which is great.
That's cool.
So I guess the quick summary of that, I'll link to the whole half hour presentation.
But it was like, Python is amazing.
We love Python.
But the web is one of the most important places where code runs right now.
And running in the browser, Python is sadly absent for the most part.
I mean, we have Sculpt and a few of those other things like PyPyJS.
But they're always in some kind of like seven caveats and some little sliver of use case, right?
What I was hoping for when I watched this was like, okay, this is the buildup.
Please let this be an announcement.
Like, please let this be an announcement involving WebAssembly.
And it just turned out to be a community.
We need to work on this.
And I thought it was really awesome when I saw Pyodide come out.
I'm like, oh my gosh, they actually were working on something.
But I guess since you didn't know about each other, you couldn't really.
It's not like you could do the big reveal of like, and Pyodide's a good start or something, right?
Yeah, yeah.
It would have been a little bit of a different talk, I guess.
Yeah.
But still, I mean, the points he makes are great points in terms of, I think, you know,
the web is where so much computing happens these days that if you aren't playing in that space,
you know, you are becoming limited.
And yeah, and like you say, there's been a bunch of other projects to bring Python to the web browser.
Yeah.
The thing that makes Pyodide a little unique is that it tries to be as close to upstream as possible.
So it's using upstream CPython, the upstream versions of NumPy and SciPy and all these things,
and tries to change them as little as possible so that the effort on those projects contributes
into our effort directly rather than reinventing and then constantly having to keep up with that,
right?
Right.
Yeah.
Like we spoke earlier, there's so much benefit to having all these packages.
And every day there's just more to grow upon.
But if your job is like, we have to have our own copy and implementation of Matplotlib in JavaScript,
like nobody wants to do that job, right?
Yeah.
That's just so many years of effort that I think, you know, it would always be a poor imitation of the real thing, right?
So it's...
Yeah, it'd also be behind as well.
Like TensorFlow came out, but we haven't written the JavaScript TensorFlow yet, so forget that or whatever, you know?
Something like that.
Right.
And you see this a little bit even with like PyPy.
I mean, PyPy is incredibly impressive.
Really cool project.
But they're still at the 3.6 level of syntax because they're just always sort of following.
It's just sort of in the nature of what they're doing.
And I don't mean that as criticism.
But if you aren't tracking the leader, you're always going to be a little bit behind, right?
Right.
So I guess before we move off of just WebAssembly on its own, I can dig into Pyodide.
How well supported is it?
Like WebAssembly sounds like new and futuristic.
How well supported is this?
It's in all the major browsers, in the stable versions of all the major browsers right now.
So it's pretty easy to rely on it.
It's at what they're calling sort of this MVP level of WebAssembly.
They sort of decided which features were the most critical, and that's everywhere.
Then there's a bunch of ways in which WebAssembly is already planning to be improved that will eventually trickle down to browsers.
So things like threading are newer features that are coming down.
And garbage collection is going to be added.
So there's a bunch of things that are coming that you can't rely on yet.
But for the core stuff, and actually for most of the stuff we needed for Pyodide, it's already there.
This portion of Talk Python is sponsored by Microsoft and Visual Studio Code.
Visual Studio Code is a free, open-source, and lightweight code editor that runs on Mac, Linux, and Windows with rich Python support.
Download Visual Studio Code and install the Python extension to get coding with support for tools you love like Jupyter, Black Formatting, Pilot, pytest, and more.
And just announced this month, you can now work with remote Python code bases using the new Visual Studio Code remote extensions.
Use the full power of Visual Studio Code when coding in containers, in Windows subsystem for Linux, and over SSH connections.
Yep, that's right.
Autocompletions, debugging, the terminal, source control, your favorite extensions.
Everything works just right in the remote environment.
Get started with Visual Studio Code now at talkpython.fm/Microsoft.
So it looks like I opened up Can I Use, and I'll put a link to the WebAssembly report for Can I Use, which talks about what browser support what.
So it looks like Edge, Firefox, Chrome, Safari, Opera, all those desktops just supported.
iOS on Safari supports it, and Android, Chrome, and Firefox there supported.
That kind of sounds like 99%, right?
Yeah, yeah.
I'm excited to see things like threading and stuff coming as well.
There's a possibility for more interesting stuff to come along.
Yeah.
Cool.
All right.
So that brings us to Pyodide.
Now, there's a couple of interesting projects that are saying WebAssembly plus other language plus interesting runtime means something in the browser.
What did it mean for you guys?
The reason Pyodide started is when I arrived at Mozilla, Hamilton, Ulmer, and Brendan Collar, and also William LaChanze and Tian Brooks were working on this sort of internal skunkworks project for data science at Mozilla.
The idea was data scientists at Mozilla were using a lot of things like Jupyter Notebooks, or there's a tool called Databricks that's very similar.
And the problem with these tools was that sharing them is harder than maybe it needs to be because you have a front end on the web, but your actual computation is happening somewhere else.
It might be on the same machine, but often it's a remote kernel somewhere else.
Right.
So you need maybe access to that compute cluster, or if you want to run it locally, you've got to pip install a bunch of stuff, right?
You're like, oh, you can run this.
It's easy to run, except for you have to now set up a virtual environment.
You probably should use Minicon.
And here's your stuff.
You're like, whoa, whoa, whoa.
I just want to look at the report.
What is this, right?
Like, for a lot of folks, that's super overwhelming.
Yeah, your choices are generally, you either require people to install, which, like you say, it's very difficult, or you have to sort of pay for some cloud computing resources somehow.
And so if you were to put that on, say, a public website to share your data science, you might end up with an unexpectedly huge bill, perhaps, right?
Right.
The worst case thing happens, exactly what you want, is a lot of people get interested in it.
Exactly.
And so the idea with iodide was, let's move all the computation into the browser, and then the computation's all happening at the edges in people's clients, right?
Right.
And to be clear for people, it's iodide, not pyodide, right?
Exactly.
This is another project.
Yeah, okay.
Yeah.
So that's iodide.
It's sort of this data science user interface front end, right?
And the first iteration of that, of course, was using JavaScript to do the data science.
And you start to realize, well, JavaScript's not a great language for that.
There's not this sort of mature ecosystem of libraries and tools you can just pull off the shelf like there is in Python or R or Julia, right?
And then there's even some kind of really nice to have language features that JavaScript doesn't have.
Like it doesn't have operator overloading, which is really handy when you're doing a lot of numerical computation.
Right.
And numbers are weird, right?
Like you can't have true integers, for example, and other stuff.
Yeah.
Exactly.
And there's a lot of movement in that space trying to make that all better.
But that's kind of a big lift.
And definitely the iodide project wants to encourage that.
And we're working on that kind of in one thread.
But in the meantime, we thought, why don't we try and come to data scientists where they are, which is in Python, and somehow bring Python to the browser.
And this seemed like a very crazy idea to me when it was first raised.
But fortunately, like I said, at Mozilla, we have a bunch of WebAssembly experts who got on a meeting with us and said, it can't be that hard.
Other people have done things much more difficult than that.
So why don't you just try it?
So I went off and found this project by a GitHub user named DGM called cPython Emscripten, which had done a lot of the initial footwork on this.
And starting with that, was able to get something going in probably a couple weeks.
That's kind of like that 80% in 20 weeks.
And then the remaining 20% is, sorry, in two weeks.
And then the remaining 20% takes forever.
But certainly getting to the proof of concept was pretty quick.
And realizing, hey, you can actually compile the real cPython interpreter and get that to run and then have the real NumPy loading in.
And all those things actually do kind of work.
It was pretty exciting.
Yeah, that's pretty amazing.
And how much of the cPython, like how big is the cPython.wasm or whatever it's called?
Like the core runtime bits you got to take down before you can start doing stuff, just roughly.
Yeah, roughly.
So I'm actually pulling up those numbers because they change all the time.
It's about 20 megabytes for Python core.
And then, of course, the libraries you're going to pull in will add to that.
So NumPy is around 8 megabytes.
It goes from there.
But one of the things that PyDyde does is it only downloads the libraries you actually import.
I see.
If you don't import Matplotlib or NumPy, like those are not things it has to go hit, right?
Exactly.
And also your browser will cache those things.
So the first time you'll pay the network penalty.
But once it's been done once, it's on your machine.
And it will actually recompile the WebAssembly each time, but it doesn't actually have to download it again.
Cool.
So that seems like a really good opportunity for a CDN.
And the fewer CDNs that host this, the better, right?
Like the more it is shared, the better, honestly.
You know, when I think about these types of things, one thing when I speak to folks like you, because you actually are within a sphere of influence that could possibly have some kind of difference.
It's cool that you can put that on a CDN and you can download it and make it go.
But, you know, what if like JavaScript is baked into Firefox?
What if CPython in WebAssembly was part of Firefox?
Like when I update Firefox, I get that latest runtime and I don't have to download it ever.
I don't know if it's a silly idea or not.
I mean, I remember from, you know, probably at least 20 years ago, people have talked about JavaScript's not a great language.
Let's put a better language in the browser instead, right?
That's been a theme for a very long time.
And what's interesting is now that we have WebAssembly, we sort of no longer have to pick one.
Which is a nice situation to be in.
We can get any of them in there.
Are there ways that it could be done like more efficiently or more conveniently?
Certainly.
Like I think, you know, maybe there'll be some like web extension you download that gives you languages so that it just kind of will always update those in the background and you don't have to worry about this kind of stuff.
There's ways that you could make it almost like a browser just with a little bit of extra added to make.
Yeah, I'm not nearly proposing Python in Firefox.
I'm proposing Firefox come with these preloaded or like you say in the background, like preload the latest one or something.
And then you could have Python.
You could have C#.
You could have all the languages that are like building these runtimes in WebAssembly and make them available.
And just I think that would be super cool, actually.
Yeah, it definitely would open up the possibility for, say, writing web applications using this technology.
So one of the things I do warn people about Pyodide is the thing that's cool about Pyodide is you can actually see the Python in your web browser and run it there, which is great for the data science use case.
Right.
But if you don't have a use case where you need to show people the code, this is probably not how you want to write your web app.
Yeah, for sure.
You probably want to stay in a JavaScript world, which is a lot more efficient and a lot faster and all these things, right?
Yeah, so Pyodide is very much focused on basically what you do with Jupyter notebooks, but make that execution happen on the client side in the browser, not connected back to a Docker thing or some kernel elsewhere, right?
Like that is the use case and that's what it's built for and optimized.
Exactly.
That's the original use case that came out of Pyodide.
What's interesting is since then, we've been talking with the WebAssembly folks again who are really pushing the idea of WebAssembly as a containerization technology.
So WebAssembly that doesn't actually run in a browser but would run on cloud computers, right?
Yes.
Because it provides a really nice sandboxed way of running arbitrary code, but it does it in a way that's actually a lot lighter weight than Docker, right?
So like Docker is maybe the industry standard for this right now, but Docker essentially you're taking a whole Linux distribution and a whole OS and shoving that in a container and passing that around.
Right.
And you require the kernels to match of the host and the container, right?
Whereas WebAssembly doesn't care.
You know, there are projects like Wasmr that are bringing this to Python already, so it's not a far-fetched idea.
No, it's not.
I think it has a lot of promise, and for our own little data science community, what excites us about it is we can use the browser as like a prototyping tool where the computation is happening locally and it's really fast, maybe while you're working on a small part of your data.
But then to be able to very smoothly say, I'm now going to run that on a cluster without having to change anything and having it still be built on the same technologies could be a really powerful thing.
This is all kind of in the pie-in-the-sky streaming of its stage for us.
Yeah, but it's a sweet pie.
It looks really nice.
Yeah.
Exactly.
You could bring in things like Dask as well to help you do distributed computation without people really even knowing or caring that that's happening.
So there's a lot of stuff that could like expand, expand to the servers, expand to clusters, and so on.
Exactly.
Yeah.
Cool.
So I've seen some cool examples of this already working.
Like I pulled up the, was it LA data or some kind of like city map, the one that came from your article that you recently published, but there's a live example and a link to that.
It's pretty interesting.
It's doing real data science.
It's doing real computation.
So it takes like 15 seconds to load, right?
Yeah.
Even if you've already cached the download, it's like computing for 15 seconds.
So you got to be patient.
But then it comes up and it's got a really wonderful graph and visualizations.
Like how do you do the visualizations?
There's probably a lot of JavaScript and other tie-ins there, right?
Yeah.
So it actually depends.
There's a lot of different ways you can do it.
But that example you're talking about with the map and the call data, there we're using a JavaScript library called Regal, which is sort of a WebGL front end to do that 3D plotting.
And it's nice because it uses the hardware to do the 3D acceleration and works really well.
But you can just as easily use Matplotlib and exact like the full Python Matplotlib and do your plotting there.
And that all works.
There's only very maybe 300 lines of code that kind of glue Matplotlib to a Web Canvas that had to be written to make that work.
But otherwise, that's pure Python doing your plotting.
But then we've also played around with tools like Plotly, which is a JavaScript plotting library.
One of the things that PyDyde does really well is it can share your data between Python and JavaScript without copying it.
So it's really fast to share the data back and forth.
So you can do like all your heavy lifting computation in Pandas in Python and then just ship that over the JavaScript side for plotting and kind of mix and match.
So it's kind of exciting that like you no longer have to say, well, I'm working in Python.
So my choices for plotting are Matplotlib and maybe Boca and whatever the Python ones are.
You can choose from both Python and JavaScript ecosystems.
Maybe in this crazy future, you could also import some other WebAssembly based visualization thing that you don't even know what it's written in, right?
Like who knows?
Maybe it's in Swift or something crazy, right?
But yeah, interesting.
Yep.
Okay.
One thing I want to ask you is like if I'm a data scientist and I'm listening to this and I'm like super excited, should I be excited today or should I be excited in like a year and a half?
Is this something I can reasonably use now or is that a cool proof of concept or like what's the status?
I would say you have to have a little bit of patience still.
Okay.
You know, we certainly encourage people to come up and try to do the kind of things they're doing in Jupyter now in iodide and pyodide and sort of see where some of the rough edges are.
We do actually have it.
It is being used for real work within Mozilla for data science and people are using the Python parts of it and stuff.
So if you sort of know where the boundaries are and what you can get away with, it's already working.
It's sharp and jagged over there.
Don't go over there.
Exactly.
Yeah, yeah, yeah.
Right.
But I would be being disingenuous if I said it was ready for everything that people might want to do.
Sure.
I guess the way you find out and the way you get it ready is people try to use it and you're like, wait, everyone's trying to do this and it doesn't do that.
Well, maybe that's something it gets.
Exactly.
No, it's really helpful for us, actually, because we've been getting some really great bug reports.
We had a blog post last week that kind of brought a lot more traffic to the site and that turned into a lot of really great bug reports of things that seem obvious in hindsight, but we had never thought to check, is that going to work?
Yeah.
That's really helpful.
And also, it helps us prioritize what features need to be added.
If 10 out of the 20 people that show up all have problems with the same thing, well, that's a pretty good sign that that's where we should focus effort.
Yeah, that makes total sense.
Are there full-time employees working on it at Mozilla?
What is its status as a project for you all?
So there's probably a total of about three FTEs working on it divided among five people within Mozilla, and it's still primarily sort of an internally devoted project in that our internal users are kind of helping us prioritize what gets worked on and move forward.
We do, of course, have the public-facing website at iodide.io where anybody can come up and create notebooks, and we do look at that, too.
And it's all open source.
Yeah.
And we're just sort of hoping that if we can bootstrap it enough internally and prove it as a useful tool, then we can get, hopefully, some more resourcing to kind of make it something that will serve a broader community.
Yeah, that's super cool.
So if I am a person who maintains or is somehow in charge of a data science package that is not available in there, I'm guessing there are some that are not available.
Is that right?
Yeah.
So if I am, how do I get mine?
Like, I run, you know, whatever.
And I really want that available alongside NumPy.
How do I make that happen?
So right now, all our package building is built as part of kind of this monolithic tree of make files.
So to add a new package, you basically add it to the Plyodide source code, and then that causes it to automatically get built and then eventually distributed.
Where I'd really like to move is to something that works more like CondoForge where, and maybe even literally to use CondoForge if we can make that work so that anybody could just walk up and contribute a package sort of in their own repo and that would automatically get picked up and then distributed.
So it would be a more like distributed build system than what it is now.
Oh, yeah.
That's pretty interesting.
Yeah.
That's a cool idea.
Yeah.
To just basically have approved sources for packages and you guys just continually pull them kind of like, like you said, like a CI system almost.
Exactly.
Yeah.
So you'd have individual package maintainers who could maintain their own package, but the sort of infrastructure that makes that all work would be centralized.
That's the idea.
Yeah.
Right.
Is it hard?
If I have something that has like some C section and some Python section, what's the overhead to get it working in this?
It varies.
So like NumPy that has C, but it's fairly straightforward.
C is not too bad.
One of the things we've really struggled with is SciPy because SciPy actually has a fair bit of Fortran.
And so Fortran is its whole other set of problems for WebAssembly.
There's basically there's not a good compiling option for anything that's not Fortran 77 right now.
So we have to kind of push that forward somehow.
So there's kind of this range of easy to hard and it's hard to know maybe up front how hard something's going to be.
Pure Python stuff is very easy.
Pure Python.
There's actually even a little helper script where if you run this little helper script with the name of the package on PyPy and it will automatically generate the make file needed to build it as part of PyDy and it automatically goes in.
You know, you submit that as a PR and you're good to go.
That's pretty cool.
So when say my Python, suppose I have a pure Python package on PyPI and I want to have it in there.
Does it get somehow compiled to WebAssembly?
Does WebAssembly itself just like become an interpreter and just use Python bytecode?
Like what do you know what the process there is?
Yeah.
So PyDyde is literally running the Python interpreter inside your browser.
So if you have a pure Python package, it's actually just shipping Python to that interpreter running in the browser.
And that's how it runs.
So it basically just works off PYC bytecode.
Exactly.
And just feeds it off to the interpreter just happens to be executing not on C but in WebAssembly.
Exactly.
That was my first guess.
But I thought maybe there's some other magic like, oh, we had to add a JIT compiler to this or, you know, some weird thing.
No.
And so for that reason, what you're getting is something that performs pretty similar to CPython, right?
Something like PyPy.js has, of course, opportunities to JIT the Python itself and potentially get a lot more performance.
So we're not doing anything sophisticated like that in PyDyde at this point.
Yeah.
So because we have a really nice JIT sitting there in the browser, it's certainly there and could be on some point.
It's certainly possible.
I know Brett Cannon worked on Pigeon, I think is what it was called.
Yeah.
Which was looking at some of the JavaScript JIT stuff and seeing how that could be applied back into the CPython runtime.
I don't know.
Maybe there's some synergy there.
Who knows?
Because it sounds like they're all kind of swimming in the same soup of ingredients or whatever.
Absolutely.
Yeah.
What does the performance of WebAssembly relative to JavaScript look like?
So if I had like my Quake example and I ran Quake over Asm.js and I ran it in WebAssembly, what would I get?
I don't actually know those numbers.
I'm sure that WebAssembly at this point is quite a bit better than Assembly.js.
The numbers I do have is what happens to Python.
So like comparing Python running natively on a machine versus inside the browser.
And you generally get anywhere between like the same speed and 12 to 20 times slower.
Okay.
And what seems to matter.
So if your Python application is mainly just calling NumPy operations, which are at the bottom sort of C tight inner loops.
Yeah.
That stuff tends to be pretty much the same speed.
Right.
Those tight C loops tend to be pretty much the same in WebAssembly as out of WebAssembly.
If you're doing a lot of looping in Python or calling a lot of Python functions, those things tend to get quite a bit slower.
And the reason is that the Python interpreter is basically calling a lot of C function pointers all the time.
That's sort of kind of how it works.
It's calling other C code through C function pointers.
Py, object, star, all over the place.
Yeah.
Exactly.
Yeah.
And calling a C function pointer in WebAssembly is quite a bit slower than it is on native.
Okay.
For reasons that I don't know if I could fully articulate, but probably partly related to the security model.
Like there's just ways in which that's a lot slower.
And unfortunately, the way the Python interpreter is designed is making lots of C function pointer calls all over the place.
Right.
But it might not matter.
It depends.
Right.
Exactly.
So it's five times slower might make it go from half a millisecond to, I don't know, 2.5 milliseconds.
And like the user doesn't perceive these or care about them.
Right.
But now all of a sudden you have this great new deployment story and this execution engine.
And like what it opens up is way more valuable than that amount of slowness potentially.
Exactly.
It's certainly within the realm of like I can live with that.
You know, it's not hundreds of times slower.
Right.
Yeah.
Interesting.
Cython.
Can I do some, like I've got some doubly nested loop and I know that that's the problem.
Can I Cythonize that puppy and then WebAssembly the result or something?
Yeah.
So Cython works just fine.
And in fact, like Pandas is largely written in Cython.
So in order to get that to work, that needed to work.
But all of that compilation happens ahead of time on the native machine before shipping it
to the browser.
We don't actually have the ability to compile Cython code inside of the browser.
Right.
But as a package developer, maybe I could leverage that to avoid the, like the really, so where
there's a penalty in Python versus C now, the penalty may be worse.
It's in WebAssembly, but maybe the answer is Cython still.
Absolutely.
Yeah.
Okay.
Yeah.
Totally.
And then of course, people have gotten the Clang compiler to run in WebAssembly.
So theoretically, we could get, we could put that there as well.
And then we could send it Cython code and get something back and maybe run that right away.
Like that's a little bit getting into crazy territory maybe, but who knows?
Yeah.
Well, it's turtles all the way down or WebAssembly is all the way down or something like that.
Right.
Yeah.
Interesting.
Both having all of this experience and expertise in Rust and Rust being so built for WebAssembly
or being so well paired with WebAssembly.
And then also some projects trying to do, say, CPython's runtime in Rust.
I guess the question is rambling around is to say, if I take Rust and like rethink CPython,
what do you think the possibilities are there in this context?
Yeah.
I mean, I think what's exciting about Rust is because it's a newer technology, unlike C, like,
it's a lot easier to get into WebAssembly because they just, there's just not as much baggage.
And that's kind of Rust's advantage on WebAssembly.
Plus, there's the fact that I think Rust and WebAssembly both coming out of Mozilla with a lot of people overlapping between those two communities has really helped that make that story much smoother.
You know, for example, if I was going to write something from scratch that I wanted to run in WebAssembly, I would absolutely reach for Rust and not C in this day and age.
It just is going to be an easier experience.
So, like you say, there's a project, maybe more than one, I don't know, that to rewrite the C and the Python interpreter in Rust, right?
So then that would help us build something like Pyodide a lot easier because it's in Rust.
We don't have to deal with a lot of the sort of niggly details we've had to deal with C.
My worry there is historically, whenever people write an alternative Python interpreter, it's really hard for it to catch on because there's so much catch up to do.
You know, if they can, I think the sort of uphill battle for that project, and I think I've read about the project and the author is like clearly doing it for fun.
Right, exactly.
You don't have to have a better reason than for fun, and I'm not trying to say that that's not a valid reason.
But, like, I think for that to kind of take over from the CPython interpreter, which I know is not a goal, it would have to, like, convince that community that's currently maintaining the CPython interpreter that Rust is going to be a better way forward.
If they can do that and sort of replace it and become the leader, that would be an amazing outcome.
But I think that's a real uphill struggle.
It would be an interesting outcome, but certainly with Rust being so new and C being so, such a stalwart, right?
Like, it's the foundation of so many things.
It would be an interesting conversation for sure.
This portion of Talk Python to Me is brought to you by Microsoft and Azure Pipelines.
Azure Pipelines is a CI-CD service that supports Windows, Linux, and Mac.
It lets you run automatic builds and tests of your Python code on each commit or pull request.
It is fully integrated with GitHub, and it lets you define your continuous integration and delivery pipelines with a simple YAML file.
Azure Pipelines is free for individuals and small teams.
If you're maintaining an open source project, you'll even get unlimited build minutes and 10 concurrent pipelines.
Many Python projects are already using Azure Pipelines.
So get started for free at talkpython.fm/Microsoft.
I guess what I'm thinking also is, like, it's interesting that people have these, hey, I want to learn Rust, and let me do that by trying to rewrite CPython and Rust.
These are interesting and, like you say, super good goals, and people, I'm sure, are getting a lot out of it.
But I'm more thinking of, like, what if you rethought what it meant to be the runtime for Python specifically optimized for WebAssembly?
You know what I mean?
You try to make it, like, 99% compatible, and so you can bring in C libraries and stuff like you can through WebAssembly.
But is there an opportunity to, like, truly rethink CPython, not just rewrite it with the different syntax and compilers?
Yeah, that's a really good question.
I think...
I don't know the answer.
Yeah.
Just interesting to think about.
Yeah.
I think one of the things that a lot of various projects have kind of worked on rethinking the Python interpreter has sort of been, what if we can assume that there's a really good JIT around, right?
That's kind of what PyPy is, and, like, IronPython, when they built it on top of the .NET CLR and those sorts of things, they sort of go, if we have a really good JIT around, what can we do?
I think a lot of times they run up against the sort of really dynamic corner cases of the Python language that are really hard to deal with there.
Yeah.
And you end up with something that's slightly different from Python.
That, to me, always feels like where it gets a little stuck.
Right.
And if there's a way of unsticking that, like, unfortunately, the community has gone through this big transition from Python 2 to 3 already, and I don't know if there's a lot of appetite for another Python that would be slightly incompatible.
Exactly.
If you could live with something that's slightly incompatible, I think there's a lot of ways you could make it more performant with some of these newer technologies.
Yeah.
I mean, maybe there's an opportunity to do that.
And maybe PyOidide's not the right answer for that because you're not looking at, I don't know, like, so much of what happens there happens in C anyway.
Like, that's where the data science action really is, and Python is kind of the orchestration layer.
Maybe it's something like, what if I could write the equivalent of AngularJS or React with an Electron app with a nice UI, but I only touch Python?
You might be willing, like, in that context to say, well, I'd rather have a 99% compatible Python with packages than just switch 100% to JavaScript as a Python enthusiast, right?
Like, that might be a cell you would buy.
Yeah.
Yeah, absolutely.
Yeah.
And the file size doesn't matter in these, like, offline Electron apps and stuff because you're already downloading, like, a 60-meg Chrome binary.
Like, what's another 10 megs that's just zipped up in there anyway, right?
Right, exactly.
So who knows?
Maybe that's an interesting corner to explore.
Not necessarily for you, but for, like, anyone interested, right?
Yeah, absolutely.
Yeah, cool.
So I guess maybe tell us a little bit about where things are going.
Like, where are you and what's the future plans?
There's a bunch of things that don't work that we'd like to work on.
So, like, currently we don't support threading because when we started the project, WebAssembly didn't support threading.
Now WebAssembly does, so it would be good to go back and kind of build on top of that.
Is that true operating system threads or is that some kind of, like, preemptive threading?
Like, what does threading in WebAssembly mean?
It's based on the web worker technology in browsers.
My understanding is they are sort of true separate operating system threads, and they're probably even more isolated than you would think of with threads.
They're kind of their own little JavaScript interpreters.
Right.
They can kind of message passing, and that's all they get for data sharing and whatnot.
Exactly.
So you can take advantage of that in WebAssembly now and pass things between web workers.
And there should be a way to kind of hopefully build the Python threading API on top of that.
It sounds almost like Python's multiprocessing more than Python's threading.
That's probably accurate.
Yeah, yeah, yeah.
But it's still, like, it's cool that it would be some parallelism that you can do regardless of how that happens, right?
Exactly.
Okay.
Another big sticking point is networking is obviously very different for Pyodide than it is for native Python, largely because of the sandbox, right?
You can't just open up a Unix socket and start writing things to it because that would be a big security hole.
So what that means is a lot of the libraries that come in the Python data science community, like Pandas, they have ways of fetching things over the network, and those don't currently work because they try to open a socket and they fail.
I see.
So building some kind of abstraction layer, maybe on top of WebSockets or maybe something else that would at least let basic things work from Python would be really useful.
Right now, generally, what you have to kind of do is do your networking in JavaScript using Fetch or whatever the tools are there, and then you can bring that into the Python side.
Right.
Axios or something nice, yeah.
Yeah, exactly.
Okay.
Yeah, but so, like, if I installed imported requests and tried to use that, for example, that might not work?
That's definitely not going to work.
Yeah.
Okay.
Cool.
All right.
So what else?
You talked about this, like, Honda Forge-like distributed build integration thing.
That's pretty cool.
What else?
There's a whole area of research we're doing around the data sharing.
So, like, I mentioned this before, like, you can have a NumPy array living in Python and pass that over to JavaScript without copying it, and that's pretty cool that that works.
But when you bring it over to JavaScript, you don't get, like, how many dimensions it has or what the shape is.
You just sort of get this one-dimensional thing because that's all that JavaScript really supports.
So we'd like to build something that kind of makes that more transparent and smooth.
Would that be like a JavaScript wrapper that kind of has an API like Pandas a little bit?
Or what are you thinking there?
Yeah, something like that, I think.
There's a project called Apache Arrow, and its sort of purpose is to allow for sharing of these data structures in memory between different language runtimes.
And they've primarily been looking at, like, native runtime space.
But they have a JavaScript implementation.
They have a Python implementation.
It should be possible to kind of bring all that into the browser and use it there.
And then, again, building on top of work already been done and not have to build it ourselves.
But there's a lot of details there.
The other thing that's sort of exciting for Arrow for us is the sort of industry standard way to bring data in for data science computation is still the comma-separated value format, right?
They're not terribly efficient to read.
They're not very space-efficient or memory-efficient.
Whereas Apache Arrow provides this sort of nice, tight binary format that we could use.
Yeah.
And that would actually allow us to sort of shove more data into the browser, which is pretty memory-limited to begin with.
So anything that will let us kind of get away from CSVs is also on our roadmap.
Yeah, just parsing all those strings is going to be a slow thing wherever.
Yeah.
And most of the libraries that do it don't.
They assume tons and tons of memory.
So they don't necessarily do it in the most efficient way possible.
They don't necessarily stream it.
They might copy the whole thing.
And then, you know, so.
Right.
Yeah.
Okay.
Yeah.
That sounds pretty cool.
And then I was looking around the site.
I found like a pretty cool demo notebook that people can try out.
I guess, you know, there's that.
And I'll put a link to that.
And what else do you recommend for people just trying to play around with it?
There's a demo notebook that kind of goes through the language features that works also kind of as a tutorial for how to get started.
But then also linked on the blog post from last week.
And maybe we can link to that blog post.
In there, there's a bunch of other demo notebooks that kind of do more real world cool things, putting stuff together.
Like you say, the call data one is pretty fun.
There's another one that I used at Mozilla internally for figuring out how to time things in Firefox.
It's kind of fun.
So if you go to iodide.io, then all the notebooks that anybody has created on that public website, they're all public.
And so you can just kind of browse through there and see what interesting things other people are doing.
Yeah.
Cool.
There's always interesting stuff happening in the data science space.
Yeah.
Cool.
One thing that I just wanted to give a shout out to, I don't know if you've even looked at it or something.
I became aware of it basically like a week ago is WASM.
So W-A-S-M is often the extension for WebAssembly.
So W-A-S-M is like WebAssembly or right?
So are you familiar with this project?
Yeah.
Yeah, I am.
To me, my first impression is it's kind of a little bit like what Node.js did to JavaScript.
Like it used to be JavaScript ran in the browser and that was like its space.
And I guess you could open the console and like type and play with it if you want.
But then all of a sudden Node.js like sprung on the scene.
It's like, wait, I can just take my JavaScript code and run it in like a server process or doing other interesting stuff just in an, like on its own.
And WASM is kind of like that for Python.
Like it will let you run any WebAssembly code regardless of whether it's this Python code or just like random WebAssembly code.
And then directly import that into your Python code.
So it's kind of more like Node enabling than it is what you're working on, which is move Python to the browser.
It's like the opposite.
Move WebAssembly to Python.
Yeah, what excites me about it actually is it's going to make languages that aren't C a lot easier to integrate in Python.
So like Rust, for example, there is a way to integrate Rust in Python that's actually pretty good and works really well.
But if the story was compile whatever you have to WebAssembly and we can get to it from Python,
I think that makes it a lot easier to have things written in whatever language is the most convenient or the most, you know, at hand.
And what also is potentially exciting from the Pydyde point of view is if this causes there to be a big sort of community of WASM packages that work with Python, we can use those in Pydyde basically for free.
Yeah, exactly.
It just grows the pie for everyone.
Yeah, exactly.
Yeah.
So I mean, I don't have a whole lot more to say than just like, hey, people, if that sounds interesting to you, check it out.
It looks like a really cool project.
And it just it's just one more sign that there's like this excitement of WebAssembly integrating with these non JavaScript, non browser traditional languages and ecosystems.
Yeah, absolutely.
Yeah.
I guess if I'm throwing out other stuff that just kind of randomly to do here, one more I'll throw out.
That's it's really, really interesting.
I don't know if you've heard of this one at all.
Blazor.
Have you heard of that?
Yes, this is the C#.
Yeah.
So they had a totally different take, but they have gotten the .NET runtime, the CLR, all that stuff running a WebAssembly.
And now you can do C# in the browser.
Their take was to build an AngularJS like framework that lets you write front end code in C# and then run it in the browser.
I don't know if that's a good idea or not, but it's, you know, it's kind of the other half of the story, I think, for Python, right?
Like right now we've got the data science, like with your work going really well.
But there's no story around like, what would I use in Python instead of Vue or Angular?
Not necessarily saying those are bad or you should, but like you could, you know, C# is showing the way like on that side of the story.
Yeah, I think there's a real advantage to having your implementation and your back end and your front end be in the same language.
I think that's kind of what Node has proven.
Right.
There's definitely an appeal there.
Yeah.
And so I think for Blazor, it's the same thing.
If you're a shop that's done your back end in C# for a long time, well, now you can have your front end in it too.
That's really nice.
One of the things that from talking to some Jupyter developers, one of the things they're really excited about with Pyodide is now they could potentially start to have some of their front end stuff written in Python as well as their back end that's currently in Python.
So because right now the world they live in is there's sort of these arbitrary lines that get drawn between what you would write in one language versus another.
And they're not always the right thing.
And sometimes you have to write the same thing in two different languages just so that you can put it in both places.
Right.
Validation or something.
Get rid of those.
Yeah.
Validation or even with Jupyter, it's certain kinds of computation that they need in the widget as well as in the back end and they need to match.
But one's written in Python.
It's not fun.
And it's just sort of this arbitrary speed bump that gets created because of the world we live in.
But if you imagine a world where all languages run everywhere, suddenly, hopefully, you're doing less work.
Yeah.
Yeah, absolutely.
And you can reuse stuff in a context where you wouldn't.
Like, until your work, it would have been kind of insane to say, well, let's reuse NumPy in the browser, right?
Yeah.
But now these doors are open.
So it just creates more synergy, I think.
It's pretty awesome.
All right.
Well, I think we're pretty much out of time there.
Yeah.
Definitely a fun conversation.
I think the future is bright.
What do you think?
Yeah, absolutely.
I'm really excited about all this stuff.
Yeah.
Same.
All right.
Now, before I let you out here, let me ask you the two final questions.
I kind of think I can guess this first one because of the way you opened the whole show.
But favorite editor for writing Python code?
Yeah.
So I use Emacs, but I actually use SpaceMax.
So it's kind of this like weird Emacs VI hybrid.
But I find it works for me.
Yeah.
Right on.
Very cool.
And then notable PyPI package?
Oh, gosh.
I mean, the one I'm most familiar with is Matplotlib because I worked on it for years and years.
And, you know, if you're not familiar with it, go check it out.
It's the kitchen sink of plotting for Python.
Yeah, it absolutely is.
And, you know, it's something exciting and like both silly but also kind of real sense.
As I saw, now XKCD style plots have come to Matplotlib.
Did you see that?
Oh, yeah.
I implemented that actually.
You did?
How awesome.
Yeah.
How hard was that?
Not too bad.
Strangely, the infrastructure that was already there kind of made it easier than it might have been.
So.
Yeah.
I mean, it looks like the sort of cartoony hand-drawn like plots and stuff.
But it actually looks really hard to do because it's imprecise and it has these imperfections, right?
It seems like it would be hard to tell a computer to be imprecise in like a human way.
But well done.
And that looks great.
So fun.
Thanks.
Yeah, absolutely.
Awesome.
All right.
Final call to action.
People are excited about iodide, pyodide.
They want to check it out, maybe contribute.
What do you got for them?
Yeah.
Check out iodide.io where you can check out all the notebooks that people have created.
And then we have a GitHub site at github slash iodide project.
Nice.
And I'll put those links in the show notes.
Are you looking for contributors or people working on it any?
Or is it kind of still an internal project at the moment?
We're definitely looking for contributors.
Find us on Gitter if you have any great ideas.
We'd be glad to help you make them reality.
Super cool.
All right.
Well, I am very thrilled to see you all working on getting this take on Python in the browser.
I think the more attempts that we have here, the better.
And it's an exciting time.
And I think it'll take off.
Thanks a lot.
It was fun talking to you.
Yeah, you as well.
Thanks for being on the show.
Bye.
All right.
Take care.
Bye.
This has been another episode of Talk Python to Me.
Our guest on this episode was Michael Dropboom.
And it's been brought to you by Microsoft.
If you're a Python developer, Microsoft has you covered.
From VS Code and their modern editor plugins, to Azure Pipelines for continuous integration,
and serverless Python functions on Azure.
Check them out at talkpython.fm/Microsoft.
Want to level up your Python?
If you're just getting started, try my Python Jumpstart by building 10 apps course.
Or if you're looking for something more advanced, check out our new async course that digs into all the different types of async programming you can do in Python.
And of course, if you're interested in more than one of these, be sure to check out our everything bundle.
It's like a subscription that never expires.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the direct RSS feed at /rss on talkpython.fm.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
I really appreciate it.
Thank you.