Episode Transcript
Transcripts are displayed as originally observed. Some content, including advertisements may have changed.
Use Ctrl + F to search
0:00
Building web UIs in Python has
0:02
always been an interesting proposition. On
0:04
one end, we have the full
0:06
web design story with artisanal HTML
0:08
and CSS. On the other end,
0:10
there are several Python platforms that
0:12
aim to bring rad rapid application
0:14
development style of building Python apps
0:16
to the web. Those
0:19
can be great, and I've covered a couple of
0:21
them, but they usually reach a limit on what
0:23
you can do or how they
0:25
integrate with the larger web ecosystem. On
0:28
this episode, we have Samuel Colvin
0:30
back to share his latest exciting
0:33
project, FastUI. With FastUI,
0:35
you can build responsive web applications
0:37
using React without writing a single
0:39
line of JavaScript or touching NPM.
0:42
Yet designers and other tools can
0:44
focus on React frontends for
0:46
a professional spa-like app experience.
0:49
This is TalkPython to me, episode 449, recorded December 14th,
0:52
2023. Welcome
1:10
to TalkPython to me, a weekly
1:12
podcast on Python. This is your
1:14
host, Michael Kennedy. Follow me on
1:16
Mastodon, where I'm at M Kennedy,
1:18
and follow the podcast using at
1:20
TalkPython, both on boston.org. Keep
1:22
up with the show and listen to
1:24
over seven years of past episodes at
1:26
talkpython.fm. We've started streaming most
1:29
of our episodes live on YouTube.
1:31
Subscribe to our YouTube channel over
1:33
at talkpython.fm slash YouTube to get
1:35
notified about upcoming shows and be
1:37
part of that episode. This
1:40
episode is sponsored by Bright Data.
1:43
Bright Data is professional web scraping in
1:45
a dataset marketplace. If
1:47
you need data and it doesn't
1:49
have an API, check out talkbython.fm
1:51
slash Bright Data today. And
1:54
it's brought to you by Sentry. Don't
1:56
let those errors go unnoticed. Use Sentry
1:59
like we do here. here at TalkBython, sign
2:01
up at talkbython.fm slash sentry.
2:05
Hey Samuel, welcome back to TalkBython to me. Thank
2:07
you, thank you very much for having me again.
2:09
So soon after last time. It's always amazing to
2:12
have you on. In fact,
2:14
you were on just last week
2:16
in a really cool show that
2:18
tons of people enjoyed and
2:20
is not yet out at the time of recording,
2:22
but will be released to the world by the
2:24
time your show goes out live. So it's a
2:26
bit of a time travel thing, very appropriate here.
2:29
But it was under the
2:31
full-time open source developer's panel of
2:33
like a bunch of folks, for
2:35
example, Charlie Marsh, Megugan, Gina Hauska,
2:38
and so on, right? And you
2:40
snuck in for a minute there
2:42
on your travels,
2:44
but now you're back and we're here to
2:46
talk properly about something really excellent that you
2:48
put together called Fast UI, which is gonna
2:51
be a lot of fun. Yeah, thanks so
2:53
much for having me. And yeah, I've been
2:55
in a slightly better environment for
2:57
a podcast than the stairwell of
3:00
a restaurant in somewhere
3:02
in Istanbul. So yeah, it's nice to be
3:04
here. High marks for effort there. Come
3:06
on, that was great. It
3:08
was good fun, but it was, this is a better
3:10
place to talk about these things. Yeah, well, I hope
3:13
you had a good trip and you're back in at
3:15
it. Kim, out in the audience, points
3:17
out, yo, hey, could you just write another impressive tool
3:19
for the next week's show? Because things
3:21
are going pretty prolifically over there. You tell
3:23
people a bit about Pydantic, the company, they
3:25
probably heard of the library, but just what
3:27
are you up to these days? So Pydantic's
3:30
obviously been around since 2017 originally, but
3:33
then it's like something weird happened at the beginning of
3:35
2021. I don't know quite what
3:37
that was, but like Pydantic, like the downloads just like
3:39
went crazy. So we were like 5 million downloads then,
3:41
and we're now at 130 million. So
3:44
like, yeah, it's gone crazy. And then just
3:46
a bit more than a year ago, I
3:48
was very lucky, Sakoya got in touch with
3:50
me and basically said that I wanna start
3:53
a company. I had been meaning to do
3:55
that after I released Pydantic V2 that I
3:57
was then working on. Yeah, started the company.
3:59
beginning of this year and now have an
4:02
amazing team of 10 people working with me.
4:04
So we released Pinellip B2 finally, having originally
4:06
told people it would take me alone three
4:08
months. It took me and just then six
4:10
people a year in total. But that was
4:12
that was released back in the summer. And
4:14
now we're working on on a platform that
4:16
I'm not going to talk about now. But
4:18
I would love it if you'd have me
4:20
back, I guess, the beginning of Q2. Is
4:22
that next week or whatever? Not
4:25
quite next week. Q2 of 2024, something like that. Yeah,
4:28
I think we're going to try and get to open beta
4:30
and in Q1. So,
4:32
yeah, OK, fantastic. Yeah, well, but off
4:35
the back of to that without getting
4:37
into details on it has platform components
4:39
to it and so we have people
4:41
people will be logging in, etc, etc.
4:44
And I was just thinking about all of the
4:47
path and the churn of building the relatively
4:49
mechanical bits of an application again with
4:52
doesn't matter actually if you're building it with
4:54
with React or with one of the other
4:56
front end frameworks, you end up having a
4:58
whole bunch of stuff duplicated between what the
5:00
front end that guys are doing and what
5:02
the full stack developers or back end developers
5:04
are building for us. And I guess
5:06
for lots of people, there's a pedantic model that's kind
5:08
of at the core of lots of those bits and
5:10
I was just reading all of that churn. And I
5:12
had been wanting to build something like first UI for
5:14
a long time. But that the fact that we're going
5:16
to be using it internally really spurred me on to
5:18
go and go and get it built and release release
5:20
it in like a very incomplete phase to see
5:23
what people thought. And yeah, it's been a
5:25
great reaction. Here I am. Yeah, there has
5:27
been quite the reaction to it. Let's see.
5:30
Do the GitHub star test. It's
5:32
two point six thousand stars and
5:34
it's what two weeks old.
5:36
Yeah, my goal. Yeah, I'm a bold last
5:39
month anyway. I was only really publicly like,
5:41
yeah, two weeks left and two weeks. Oh,
5:43
that's right. Yeah,
5:45
you probably so you worked on it
5:47
a little bit private and then you flipped a
5:49
bit on the public status. Yeah, that makes a
5:51
lot of sense because you want people just go, whoa, what
5:54
are they building? Maybe you do. What is
5:56
this GitHub repo? They misspelled
5:58
fast API. I don't know. they're working on.
6:00
Yeah, exactly. And also,
6:02
I mean, we have a team with lots
6:04
of people who've done lots of open source,
6:06
very strongly opinionated. I can't even
6:09
get my team to use it without kind
6:11
of proving the value in it. So I
6:13
worked on it a bit without really talking
6:15
to them. And then was like, right, I
6:17
built this thing, let's at least give it
6:19
a try. Yeah, I don't know, maybe maybe
6:21
I'm wrong in this. But I think it's
6:23
quite a fundamentally different way of thinking about
6:25
how you build user interfaces from from lots
6:27
of the tools that exist today in the
6:29
Python ecosystem. And so there's a bit of
6:31
a like education piece. And they're trying to
6:34
understand the principle, as well as the like
6:36
mechanics of going and using it. Yeah, absolutely.
6:38
Well, we're going to dive into the
6:41
philosophy, but I'll give people that too
6:43
long didn't read version. Basically, you can
6:45
create us in pure Python in sort
6:48
of dynamic web framework friendly ways,
6:50
right? Yeah, probably the mistake is in
6:52
my description of it. Because yes, it
6:54
does that. But where I I personally
6:56
think fast UI is powerful, and where
6:58
we're using it in within the pandemic
7:01
team is actually, we have got front
7:03
end developers, we've got some really expert
7:05
guys, like who are very comfortable building
7:07
stuff in React. But we want to
7:10
those two roles that have to constantly communicate to
7:12
build every every individual bit. So the idea is,
7:14
I think if you go down the page a
7:16
little bit, I kind of explain it. But like
7:18
for a for a Python developer, if this way
7:20
of building us without having to touch touch
7:23
groups or JavaScript or NPM or any
7:25
of those for zan time, like massive
7:27
build tools, but then for a front
7:29
end developer, it's this opportunity to go
7:31
and build the best components you can and
7:33
allow a promise you provide
7:35
a powerful interface for for your back end guys to
7:37
go and build the build the UI with it. So
7:39
kind of split those two things up. And I guess
7:42
allow react to do what react does brilliantly,
7:44
which is allow which is provide these like
7:47
reusable components. Yeah, absolutely. Kind of a framework
7:49
as well to bring the navigation and the
7:51
cohesion of of the whole app together, not
7:53
just a particular view or page to you
7:55
would say, right? Yeah, yeah. So the weird
7:58
bit is principle of restful. We've
8:01
all heard of REST or RESTful and we all
8:03
think we know what it means, which is basically
8:05
something to do with the URL structure and return
8:07
me some JSON that gives me the data I
8:09
need to render by view. Well, if you look
8:12
at the Roy Fielding's
8:14
original PhD, as is brilliantly described in this
8:16
HTNX article that I talked about further on
8:18
down here, he's not really talking about that
8:20
stuff. Sure, he has some stuff on what
8:22
the URL structure should be, but really, his
8:25
principle is that the data
8:27
returned from the backend should be
8:29
self-describing. It should have everything you
8:31
need to go and render the user interface.
8:33
Let's say, I think they're using
8:36
the HTNX example, example of like a
8:38
bank account. If
8:40
you go down to like principle, the long version, here
8:42
we are. I've linked to the
8:44
PhD, but more importantly, the HTNX article, which explains
8:46
it really well. I think if
8:48
we follow that, yeah, I think they'll even on that page,
8:51
there's a very have a jokey tone lots of time HTNX,
8:53
but they also have a really cool thing. Yeah,
8:55
absolutely. I think they have, yeah, here we are. If
8:58
you look at the traditional JSON response, which I
9:00
think is the second one, and you were trying to
9:02
show, yeah, right. This, you and
9:04
I as humans can read this and be like, yeah,
9:06
that kind of explains my bank account and what's going
9:08
on. But there was not enough. Right, it's got like
9:10
an account number and a balance, which is a more
9:13
complicated object, nested objects, and those types of things. Right,
9:15
it's got all the things that we can read account
9:17
number, call that the number, balance, yeah, that makes sense.
9:20
If you're a computer, there's not enough there to
9:22
go render someone the nice user interface they would
9:24
want where they would have it just laid on
9:26
a page. So if you were the engineering team
9:28
in the bank trying to turn this into a
9:30
web interface, you
9:33
then need to go and have lots of
9:35
very application specific or page specific logic to
9:37
show where the account number goes and where
9:39
the balance goes and where the status goes
9:41
and stuff like that. And that causes enormous
9:43
amounts of churn. And it means that it's
9:46
particularly difficult when you have those engineers working
9:48
in time zones because you end up having
9:50
this spec between the two. And then you
9:52
always have this problem with software where, fine, we can get it
9:54
to work, but what happens when we come to add it? So
9:57
what's the process of, let's say we want to show
9:59
as well on on this page, you're like joint
10:01
account balance, let's say, just to make something
10:03
up. What we probably need to do is
10:05
we need to get back end guys to
10:07
go and add that to endpoint and then
10:09
the front end, and that can
10:12
be deployed and then the front end can
10:14
be updated to show that and the data
10:16
is available. That is a lots of churn,
10:18
lots of delay in that. Right, lots of
10:21
coordination between the two domain experts and then
10:23
it kinda, you got that microservice cascading, like
10:25
it's gotta do, then this one's gotta be
10:27
upgraded and then eventually there's enough flow of
10:30
data through the system that the UI people
10:32
can put it up there, right? Right, and
10:34
so, and it's bad in this case of
10:36
like showing your bank balance, but it gets
10:38
even worse when you have a form where
10:40
every field in the form needs to be
10:42
completed, for example, and so
10:44
we basically have to deploy the front end that
10:46
has all of the form components and the back
10:48
end that receives that new form at
10:51
the same time. And we've got this planatic
10:53
model that, depending on how we've done it,
10:55
probably is used to define our form and
10:57
it might even be used to define our
10:59
database, but like with not using a
11:01
planatic model in the front end, TypeScript, in
11:03
my opinion, is a big appeal in typing
11:06
is that you don't have any, you can't
11:08
use type ins at runtime and so we
11:10
don't have an equivalent of planatic and so
11:12
we're basically trusting that data is how it
11:15
is. So yeah, fast API is an attempt,
11:17
sorry, fast UI is an attempt to basically
11:19
remove that need to like
11:21
have complete synchronization between back end
11:23
and front end by having beautifully
11:26
designed components in the front end, not saying what we have
11:28
now is that beautiful, but that's the idea locked
11:30
in, but then the back end can basically
11:33
just can do the orchestration, can say show
11:35
me a table, show me a form, show
11:37
me a modal and put the following content
11:39
in it, et cetera. Excellent, nice comment from
11:41
Tony on the other hand, says I originally
11:43
started in Python and went to using TypeScript,
11:46
Pythonic made the transition back to Python so
11:48
nice and so in your
11:50
description, you also have up here that this Pythonic
11:53
is interesting, is involved here, what
11:55
is the role that Pythonic plays
11:57
in defining all this? So the idea is that we're...
12:00
getting to of this RESTful UI is
12:02
really that we end up having a
12:04
bunch of components in a
12:07
shared definition of some components. And we basically
12:09
promise that the backend is going to send
12:11
data that matches the types defined
12:13
in the frontend. That's all very well, but
12:15
if you're not careful, you end up not
12:18
sending quite the right data. So what's nice
12:20
is that all of the components that you
12:22
can return from fast UI are themselves, high
12:25
logic models. And so high logic goes off
12:27
and does not only the validation,
12:29
but also the coercion and it does
12:31
stuff like uses camel case so that
12:33
frontend developers are happy because we've got
12:35
every no underscores anywhere. And so yeah,
12:37
all of the frontend, sorry, the backend
12:39
code for fast UI is basically, it's
12:41
just high logic models, which would implement
12:44
these components. Right? So it might be
12:46
useful for those who can see this
12:48
to go in and it'll, I can
12:50
talk through an example if we go
12:52
into the code here and I can
12:54
talk you through like a very basic
12:56
component, or maybe it'd be, I showed
12:58
it here. So I've got, got
13:00
the code base open here, just working on
13:02
something. But if I open up here, source
13:04
and then the Python package, and then we
13:07
look into components and we can
13:09
look at like a really simple component, probably
13:11
a button, which would be kind of understandable
13:13
to everyone. Where's button? Here we are. So
13:15
this is just a plain pedantic model, which
13:17
contains text, which is the text you would
13:19
put within the button. Then it contains the
13:21
event that you want to fire when someone
13:23
clicks on it and HTML type,
13:26
which, you know, and this matches what you
13:28
can get in HTML button, reset, submit,
13:31
and then class name, which becomes the
13:33
classes that get, get applied. And then
13:35
critically this type, which is a literal,
13:37
which has to be button. And that
13:40
is used by the discriminated union in
13:42
pedantic to do the validation of
13:44
different types. And it's also used by a
13:47
big switch statement in the, in the typescript
13:49
to basically decide what component I'll go and
13:51
render when I, when I get what that
13:53
an object, when I get an object. Right.
13:56
So there's some typescript, maybe it makes sense
13:58
to talk a bit. about the
14:00
building blocks. So you say fastUI is made
14:02
up of four things. Just so people can
14:04
get a sense of like, what's
14:06
at play here? Right, so the
14:08
four things that we have now,
14:10
package, Python package called fastUI, which
14:13
I was just showing you there
14:15
the types for. And then we
14:17
have NPM package called fastUI again.
14:19
It's in the Pyreantic organization, which
14:21
is where the meat of the
14:23
logic resides. And that's implementing basically
14:25
the most of the components and
14:27
all of the wiring to
14:29
mean that when I return a button, a
14:31
button, the button component gets rendered. And
14:33
then, but obviously we don't probably want
14:36
to end up using a vanilla button
14:38
when we come to display it. So
14:40
then I implemented basically customization of the
14:42
fastUI React library using bootstrap. So all
14:44
that's really doing is it's deciding what
14:47
classes to append to use with each
14:49
component and also just customizing a few
14:51
of them. So for example, modal, there's
14:53
no like nice way to do a
14:55
vanilla modal. So the modal in the
14:58
default fastUI VM package just
15:00
basically shows me alerts saying this isn't
15:02
implemented, whereas the bootstrap one uses a
15:04
nice bootstrap modal. And then we have
15:07
finally fastUI prebuilt, which basically uses
15:09
the fastUI package, customizes it with fastUI
15:11
bootstrap, and then builds it. And that
15:13
means we can go and basically return
15:17
that prebuilt React app without having
15:19
to get our hands dirty with
15:21
NPM on yarn and right and
15:24
all the other. All the webpacky
15:26
bundling, minifying, transpiling
15:28
business. The cool
15:30
bit in my opinion of fastUI is
15:32
that at its core, it's really the
15:34
definition of a bunch of different schemas
15:36
effectively. Those schemas are defined in Pydantic
15:38
and they're defined in TypeScript, but they
15:40
could perfectly well be, and
15:43
really nicely, I just merged this the other day. We now
15:46
use the JSON schema generated by
15:48
Pydantic and JSON schema generated by
15:50
the React types to
15:53
basically go and test that there's an equivalent
15:55
between those models everywhere. In theory, there's nothing
15:57
to stop the front end from being built
15:59
with a... another JavaScript library or even
16:01
with something like HTML and HTML X or
16:03
even you could go and use React Native
16:06
and build or even some kind of embedded
16:08
device. You could go and implement those components.
16:10
And then on the other side, and this
16:12
is even more achievable, you could go and
16:14
return data that
16:17
matches those models from a Rust
16:19
or Go service. And in
16:21
theory, you don't have to change your UI at all
16:23
because all you're doing is I promise that I'm going
16:25
to match these schemas and then whatever
16:28
front end and whatever back end can then
16:30
communicate. Whether that comes to pass, I don't know
16:32
yet. And obviously I built the default back end
16:34
in Python because that's what I made best and
16:36
where I think Pythonics is really helpful. And
16:39
I built the first front end in React
16:41
and TypeScript because one, that's what I know
16:43
and two, it's what we're using within Pythonics.
16:45
But you asked, lots of people have asked
16:47
about HTML X, people have asked about Svelte
16:50
and others. I think I wouldn't
16:52
see the point in building fast UI in view
16:54
because I don't think it adds much. It's just
16:56
a lot of work. I think there's a world
16:58
where we build an HTML X template
17:00
render version of fast UI's
17:03
front end that could be super valuable. That's interesting. So
17:06
first point is these different components sound
17:08
like they are potentially a little mix
17:11
and match. You could take it
17:13
all as one big thing or you could say, really
17:15
like the way it defines the React front end, but
17:17
we're going to implement it some other
17:19
endpoint. Yeah. I think
17:21
it's something like, it'll be slightly skewed now
17:23
because of tests, but I'd say it's sort
17:26
of twice as much front end to back
17:28
end at the moment as in the skewed
17:30
a bit by test, but even now there's more
17:33
TypeScript. So I think the simplest thing to do
17:35
and you could do it pretty trivially would be
17:37
to use another backend, another language
17:39
for your backend service. And as long as
17:41
it matches those types, you could even go
17:43
and use something like JSON schema to enforce
17:45
that. But yeah, re-implementing the front end, probably
17:47
a bigger piece of work, but totally doable.
17:49
I mean, I did it in my spare
17:52
time in two weeks, built the whole thing.
17:54
So it's not millions of different things. There's
17:56
kind of 20 components at the moment that
17:58
are then composable to build. reasonably
18:00
sophisticated like UIs. So this is
18:02
a web front end like Flask
18:04
or Django sort of framework, but
18:07
a way that really incorporates building
18:09
the UI in Python and validating
18:11
and enforcing that with Pydantic rather
18:13
than just hey, file new HTML,
18:16
let's just start typing and hope
18:18
they line up. You know,
18:20
like instead of trying to juggle all those different
18:22
languages, CSS, HTML, all
18:25
the JavaScript tooling for packing up stuff, just
18:27
let's write Python, right? So maybe you have
18:30
a simple example of what it looks like
18:32
to define a real simple
18:34
example here on the
18:36
readme. It's got a very
18:38
interesting parity between what is
18:41
in the HTML DOM and
18:43
what is in the Python
18:45
abstract syntax tree, I
18:47
guess, right? In visually as
18:49
well, the way you look at the code, it looks like
18:51
the way it might look in HTML. Like
18:54
give us a sense of what writing a UI
18:56
in this would look like. Right, so I think the first of
18:58
all, we have to talk about like the two enormous the
19:00
two most obvious pitfalls for this. One
19:03
end of the of the pitfall you have,
19:05
which which I think is the like the
19:07
biggest temptation is to basically mirror all of
19:09
HTML in Python. And for those of us
19:11
who are happy writing HTML or writing react,
19:13
that sounds like hell. It's going to be
19:15
slow because you have to do some weird
19:17
rendering. But it's also just going to be
19:19
a pig because I don't want to have
19:21
to define every A, H ref and everything
19:23
else in Python code. It's just and they
19:25
were going to be it requires for start
19:28
requires you to know two things Python and
19:30
HTML, whereas HTML, you only need to
19:32
know one. This
19:35
portion of talk Python me is brought to
19:37
you by bright data. Bright
19:39
data helps you turn websites into
19:41
structured data. There's an
19:43
unimaginable amount of data available on the
19:46
internet. And we're lucky to live in
19:48
a time where we have so many
19:50
API to access structured data. But
19:53
the truth is that most of the data
19:55
out there is not served up over a
19:57
clean API, just sitting there on
19:59
a web. web page as HTML. Maybe
20:02
it's even further obscured behind some
20:04
frontend JavaScript framework like Vue or
20:06
React. What if you
20:08
need access to that data? Web scraping
20:10
to the rescue, right? Yes,
20:13
but just like you wouldn't
20:15
set up your own production infrastructure in your
20:17
home office, running a web scraping
20:19
job on a single computer at a
20:21
fixed location can lead to your program
20:23
being unreliable with data pinned to that
20:26
IP's location and much of the time
20:28
blocked for rate limits and other such
20:30
causes. If you need to
20:32
do professional web scraping, write data is the
20:34
place to start. They have
20:36
award-winning proxy networks and powerful
20:38
web scrapers. What's more
20:40
is they have ready-to-use data sets for
20:43
download, so you might not even need
20:45
to scrape data at all. And if
20:47
you can't find the data set in their
20:49
marketplace, they'll even build a custom data set
20:51
for you. From listening to the
20:54
show, you know that I'm a privacy-conscious person,
20:56
and that's why I'm happy to
20:59
see that they are both CCPA
21:01
and GDPR compliant. Write data has
21:03
both low-code solutions as well as
21:05
Python programming models with async, IO,
21:07
and Play Write. So if
21:09
you have serious data needs and those
21:11
websites don't offer APIs, then
21:14
you need bright data. Check them
21:16
out today at talkpython.fm slash brightdata.
21:18
And please use that URL.
21:20
That way they know you heard about them
21:23
from us. That's talkpython.fm slash
21:25
brightdata. The link is in your podcast
21:27
player show notes. Thank you to Bright
21:29
Data for supporting the show. I
21:33
always find these things that try to dodge,
21:35
like dodge the fact that HTML exists. I
21:37
find them, I just, they
21:39
don't resonate with me. I'm not entirely sure
21:41
why. It's like we have really nice things
21:44
like CSS and we have really,
21:46
there's just so much tooling
21:48
and frameworks, you
21:51
know, we mentioned BruteStrap already, right, that just
21:53
plug into there. And if it's like, well,
21:55
we're just going to write, recreate it in
21:57
Python, well, it has all the oddities of
21:59
HTML. if it's going to be really high
22:01
parity and then you just have a less
22:04
well-known way to do the same weird thing. I
22:06
don't know. It doesn't resonate super with
22:08
me. I agree. And I found the same
22:10
thing at times with ORMs. The
22:13
worst case of an ORM is you work out
22:15
what you need to do in SQL, then you
22:17
try and translate back from SQL to ORM and
22:19
it would be much nicer just to write my
22:21
SQL. I mean, not always the case. ORMs can
22:23
be powerful, but I think that they both can
22:25
fall into the same trap as your nut castle.
22:28
And I was going to say, at the far end of the spectrum, the other end of the spectrum,
22:30
you have, and I guess Django's admin view
22:32
for understandable reasons could suffer from this, that
22:34
you basically have a very small set of
22:37
things. You have a table page and a
22:39
details page and a form page and that's
22:41
kind of it. So there's this difficult trade-off
22:43
and where in that continuum do we try
22:45
to choose what size of component to implement.
22:48
So for example, here we have the heading,
22:50
which is almost one for one matches what
22:52
you would do in HTML. We have the
22:54
text that goes within it and we have
22:57
the level, which is slightly different syntax but
22:59
it's basically one for one matching
23:01
an HTML tag. But then we have a
23:03
table, which it doesn't look very much like
23:05
an HTML table at all. We're not having
23:08
to explicitly define the table body versus the
23:10
table head. We're not having to put in
23:12
each column. We're not having to worry. Yeah,
23:14
there's lots of stuff here that is much
23:17
less like it. And that's where it's in
23:19
these very common components where there is consistent
23:21
things that lots of people want to do
23:23
or lots of places in your app where
23:26
you might want to do them where I
23:28
think a framework like FastUI gets super powerful
23:30
because we can get you a table
23:32
here with users defined and
23:34
with a few columns with some customization on
23:37
what happens when you how we render each
23:39
column much more quickly than we could go
23:41
write out all the HTML for that. And
23:43
it's much more concise to read. It's
23:46
consistent enough that something like GitHub Copilot will
23:48
help you write it out where you do
23:50
have a bit of customization to do. I
23:53
think this is where it can be
23:55
super powerful. Yeah, it is pretty interesting.
23:57
I like the hierarchy. For people listening,
23:59
just check out. github.com/Pythonic slash fast UI
24:01
and the example right there on the
24:03
page. But what you do is you
24:06
create a, in this case, a fast
24:08
API endpoint and then you return a
24:10
hierarchy of elements out of fast UI. So
24:13
we have a page, the page has components,
24:15
the components are a list of a header
24:17
and a table. The table has
24:19
data which maps over to a list
24:21
of Pythonic models which then help save
24:23
what goes in the field and for
24:26
the column headings and things
24:28
like that. Which is pretty interesting. I think
24:30
it's neat. Yeah, and obviously we can
24:32
add other components like pagination that works. I think
24:34
just to come back to the top to how
24:37
we do these views. The very
24:39
simple and it's most simple fast UIs
24:41
React app does is it basically takes
24:43
whatever the URL is you go to.
24:45
So in this case, you might go
24:47
to slash to the base URL and
24:49
it prepends slash API and makes
24:52
a request to that endpoint to basically say,
24:54
what should I render? And it gets back
24:56
to this. Here we're basically
24:58
returning a list of Pythonic models. All
25:00
that the fast UI model is really
25:02
doing is taking that list of Pythonic
25:04
models and calling model.json on it to
25:07
get the JSON that we return to
25:09
the front end. As I said, the
25:11
front end then knows how
25:13
to render each of those. Each
25:15
dictionary in the list is what it is. It's
25:18
called, it's a list of objects to use
25:20
JavaScript parlance. It just knows how to render
25:22
each of them and it renders each of
25:24
them in turn. And then obviously they can
25:26
then have nested other models, all of which
25:28
it knows how to render. Yeah,
25:30
it reminds me of a couple of things. I
25:32
have an example of this somewhere along here. I pulled it
25:34
up. It reminds me of
25:37
kind of what React looks like.
25:39
People have done React, you write
25:41
a function that returns kind of
25:44
an HTML thing, but then it
25:46
has JavaScript arrow function, right? But
25:49
it has the same nested feel, right? Did
25:52
React inspire you to create it this way or not really?
25:55
Yeah, it did. I've done quite a lot of React and I liked
25:57
it a lot. I know there was, as a result, I've done a
25:59
lot of React. popular piece of technology, there were lots of
26:01
people who liked to berate it, but I do think
26:05
React is a powerful step forward. The
26:09
greatest form of flattery is copying,
26:11
and there are enough other, sure
26:13
there are other more powerful, arguably
26:15
more powerful, arguably more performant new
26:18
front-end libraries, but everything is component-based
26:20
now. React just changed
26:22
the key change in how we did
26:24
front-end with that component architecture, and JSX
26:26
similarly is super powerful. So one of
26:28
the things that I think we're going
26:30
to get to, I don't want to
26:32
dive into it yet, but in React
26:34
you would say we're going to return
26:36
a photo context, or a switch,
26:39
or something that is not typically known
26:41
in HTML, and these are higher order
26:43
building blocks in the UI space, right?
26:45
So when people think about what
26:48
they're creating here in Python, it's
26:50
not just the fundamental DOM objects and
26:52
elements, is it? Right. So that was actually,
26:54
yeah. So page here is a bit of
26:56
ambiguity about how we're going to define a
26:58
page. Default implementation does
27:00
something reasonably sensible, like pads it, etc.
27:02
But there isn't much to do really,
27:04
you're going to return a heading, but
27:07
when you come to a table, there's
27:09
a lot of debate about how you're
27:11
going to do that. And then when
27:13
you move on to even higher order
27:15
components like a modal, then that's how
27:18
exactly that's implemented. In
27:20
some sense it's completely the choice of how you've implemented
27:22
it in the front-end. You could do lots
27:24
of different things, but yeah, the whole point
27:26
is that it doesn't and shouldn't be like
27:28
each HTML tag is written up. Because as
27:30
I say, I think that would be a
27:32
like obvious failure mode for this. Yeah. The
27:34
other thing this reminds me of, by the
27:36
way, just for people out there listening, is
27:40
that it looks a lot like a
27:42
flutter. If people have done any flutter,
27:44
you've got these widget hierarchies, you build
27:46
them, you maybe set some properties, you
27:48
add in a bunch of elements,
27:52
set some children to an array of other
27:54
sub elements. And this is done, of course,
27:57
in Dart, but it's now this is kind
27:59
of a PyDance. Python version that's
28:01
similar as well, these higher order widgets.
28:03
Yeah, absolutely. Similar thing. And
28:05
actually, the other place where I felt
28:07
this before is that internally, Pythonic core,
28:09
the Rust bit of Pythonic is effectively
28:12
not entirely different to this, right? You
28:14
define these nested structures of
28:16
different validators. Everything at its core
28:19
is a combined validator, which is, in
28:21
Rust terms, an enormous enum of all the
28:23
different types of validator, some of which have
28:25
nested within them more and more validators. And
28:27
that's how you build that nested structures
28:29
of Pythonic models, which in turn is
28:32
what these are. We're getting
28:34
the validators in the UI that kind
28:36
of like have a similar structure. A
28:38
bit of a sidebar, just a bit
28:40
of piece of code in here. You've
28:42
got table to the class, square bracket,
28:44
user, which is another class, square bracket.
28:47
I imagine that you and your team
28:49
are deeper into the Python type system
28:51
than the vast majority
28:54
of others out there. With all the work
28:56
with Pythonic and the interoperability with Rust, what
28:59
does that tell people about this? Yes,
29:01
the table is generic. So if you can
29:03
imagine if you were doing list of ints,
29:05
you would do list square bracket ints. And
29:08
that's basically the point is that list
29:10
is generic around its elements, same as
29:12
a dict is generic around its keys
29:15
and its values. Well, table
29:17
here is generic around the Pythonic model
29:19
that you're using for each row. And
29:23
particularly what that means is that what it
29:25
means practically is that table has access to
29:28
the class when it's deciding what the
29:30
default columns are. So if you don't
29:32
define the columns list as we have
29:34
here to say what columns to display,
29:36
it will show all of the fields
29:38
in the Pythonic model. And the point
29:40
is we get access to that to
29:42
the user before we've even if even
29:44
if data was empty before the validation
29:46
does happen. Is it
29:48
necessary? It's slightly like, yeah, fancy
29:50
use of Pythonic types. Python types,
29:52
maybe it is. But
29:55
yeah, forgive the Pythonic team or me
29:57
in particular occasionally doing fancy things with
29:59
Python types. That is definitely occupational hazards
30:01
of what we do. Yeah, I didn't
30:03
mean it as a negative. I just
30:05
thought it was interesting. No, I agree.
30:07
And actually I had it somewhere else
30:09
on forms and I removed it and
30:12
realized it was unnecessary. So you can
30:14
definitely do such a thing as too
30:16
much Python typing. Yeah, yeah, for sure.
30:18
It is pretty interesting. So let's maybe
30:20
talk about some of the examples. Actually,
30:22
before we do, just give us a
30:24
sense of where does this fit in
30:26
the UI space for Python. On one
30:28
hand, we've got Flask, Django,
30:30
FastAPI, returning HTML, etc.
30:34
Where it's all on you. You're doing all
30:36
the five languages of web
30:38
apps, SQL or some query language, Python,
30:41
JavaScript, CSS, some other tools, right? Like
30:43
you're doing all that and you're doing
30:45
my hand. On the other end, we've
30:47
got tools that are pretty cool. Like
30:50
we've got Anvil that lets you just
30:52
write Python and do a draggy-dropy sort
30:54
of thing, which is really neat. But
30:56
it fits into kind of a box
30:59
for those types of apps. I just
31:01
discovered DropBase. Have you heard of DropBase?
31:03
Not seen DropBase. Yeah, you've seen a
31:05
lot of these like get me a
31:07
UI more quickly. A lot
31:10
of them are like kind of low code. Anvil, maybe I wouldn't
31:12
really quite put it there, but they're pretty low code. But
31:14
then there's places where Python goes to make
31:17
it dynamic, right? So where in that spectrum
31:19
would you put FastUI as it is today?
31:21
Interestingly, and one of the reasons I wanted
31:23
to come and talk to you was I
31:25
heard you were talking the other day on
31:28
your other podcast, and I heard you talking
31:30
about FastUI and kind of I'd
31:32
take categorizing it into that group. And
31:35
what I wanted to kind of one of
31:37
the things I wanted to come and say
31:39
was, yes, we can do that. But the
31:41
use case we have within Py Atlantic is
31:43
actually to go and build a pretty complex,
31:45
fully fledged application with front-end developers building components.
31:48
But just get rid of that churn. Right.
31:50
Something more like Gmail, less like here's a
31:52
table that I can click on and see
31:54
some related table. Right, exactly. And then
31:56
what I should probably put in the demo and probably
31:58
where I'd like to add that. is people most
32:00
associated and where this is going to be most
32:03
useful is within forms. So I don't know if
32:05
you want to go to the demo and I
32:07
can talk people through but like within fast
32:10
UI is dedicated to forms. We can
32:12
do things like nested pedantic models all
32:14
become components within a form. And obviously
32:17
we can do client side validation with
32:19
a whole bunch of stuff, but we
32:21
can also do server side validation. But
32:23
then we get all the fancy stuff
32:25
like if the data is invalid and
32:27
you get a validation error on the
32:29
server side, we'll then basically re-render the
32:31
form with the errors in place. All
32:33
that stuff that like anyone building a
32:35
web application has to go and implement
32:37
some version of it. At the moment
32:40
there are some React libraries that will
32:42
build you a form from JSON schema
32:44
but they don't perfectly fit in with
32:46
what pedantic does or with fast API.
32:48
And so I have built some variant
32:50
of that about five times. I still
32:52
think the state of the art until
32:54
now is Django but like lots of
32:56
us don't want to build our web
32:58
applications completely with Django because it's
33:00
pretty all or nothing despite the wonder that
33:02
is Django. And so that's
33:04
the kind of space where for me this becomes
33:07
a really stands out because what would have
33:10
been to do it properly it's days of
33:12
work to get form submission to work, get
33:15
client side validation, server side validation, get the redirect
33:18
after your form, none of that stuff is
33:20
entirely trivial even for those of us who've done
33:22
it before. Because the theory
33:24
is the fast UI and although
33:27
fast UI does not require fast API, the
33:29
form stuff is quite
33:31
tightly integrated with fast API and
33:33
you can get a really good
33:35
experience of building stuff like forms.
33:37
I think that where the alternative
33:39
really today is to use no
33:42
disrespect to any of the fast libraries or any
33:44
of the other things but I think the only
33:46
real alternative right now is
33:48
implement it yourself or use Django. Yeah but I
33:50
do also want to but maybe before we get
33:53
to that let's try to take a little survey
33:55
of what are these widgets, these building blocks that
33:57
you can use. Is that right? Yeah absolutely. I
34:00
think I can find them here, yes. Yeah,
34:02
so you've got a fast UI
34:04
demo, which I'll link to at onrender.com,
34:06
the prefix. But you
34:09
talk about some of the things that
34:11
you can just create in that Python
34:13
hierarchy that you return that builds
34:16
up your UI there. So maybe will you
34:18
talk us through some of the things that
34:20
are here? Yes, we have the kind of
34:22
generic markdown component, which will go off and
34:24
renders the markdown. This table itself is implemented
34:26
using the markdown component. Just a one side
34:28
note, the markdown and the code because they
34:30
have quite a lot of JavaScript associated with
34:32
them. They're actually lazily loaded to make the
34:35
pre-built a
34:37
fast UI app faster to load. Then we have
34:39
text, probably the simplest one of all, just renders
34:41
and text. Paragraph, again, very simple. Page titles, a
34:44
slightly funny one. It doesn't actually display anything on
34:46
the page, but it changes the browser title, so
34:48
what you see in the tab at the top
34:50
of the page. It's not always easy to do.
34:53
How do you inject it into the head when
34:55
you're in the body? It takes
34:57
a little bit of integration there, yeah. Right, exactly.
34:59
Heading again, very simple, like one to
35:01
six HTML heading. Code, bit more sophisticated.
35:03
And if you click on code, maybe
35:05
those who can see it will be
35:08
able to click through. Code is
35:10
there. We get
35:12
a highlighted bit of source
35:14
code displayed. It's color
35:16
coded with class types
35:18
having a color, keywords having a color. That's
35:20
nice. Like you would see in GitHub
35:22
or something like that. So again, that should just
35:24
work out the box. Let me have some components
35:26
like a link list and link which are
35:29
used in other components mostly. So if you use the
35:31
nav bar, you see at the top of the page there that uses
35:33
the link list. And then we have links.
35:35
Then we get into kind of more sophisticated components.
35:37
So the first one, you see a button which
35:39
loads a modal and then the button which loads
35:41
a dynamic modal. So when the modal loads, it
35:44
will make a request to get the content you
35:46
want to see within that modal. That could be
35:48
a form or it could be customized depending on
35:50
the form in the page. Then we have loading
35:52
content from the server, which is the same thing
35:54
we were doing in the modal, but on the
35:56
page. Then we have this SSE component. So again,
35:59
very simple to use. within fast UI
36:01
but quite a lot of work to
36:03
use server side events to basically dynamically
36:05
update a React component if you weren't
36:07
using that. So your server load SSE
36:10
widget, that provides like you said server
36:12
sent events, which I don't know how
36:14
many people are familiar with SSE. I'm
36:17
sure they're familiar with web sockets and they're
36:19
familiar with just like a JavaScript event but
36:21
this is like an intermediate sort of lightweight
36:23
one directional but normally the opposite in reverse
36:25
I guess from the server to the client
36:27
sort of pushing out stuff, right? So that's
36:30
a really powerful thing and if it's that easy
36:32
to just hook a function call when something happens,
36:34
that's pretty cool. One of the things I want
36:36
to try with SSE that I think will work
36:38
really nicely is LLM responses where you get like
36:40
one token at a time because you don't want
36:42
to waste the whole thing. Yeah. The
36:44
events would be perfect for basically printing out the
36:46
response from an LLM and again it would be
36:49
like two lines of code to add that to
36:51
an app with fast UI, it would not be
36:53
two lines of code to go and implement that
36:55
yourself whether you're using your JavaScript or React or
36:58
whatever framework. Then we have
37:00
iFrame which again kind of maps, we're back to kind
37:02
of mapping one to one to component one and the
37:04
nice thing to say about both iFrame and Image is
37:06
they were contributed by other people so I don't think
37:08
I'd even created an issue asking for them but people
37:10
come along and add to them, it's been one of
37:12
the nice things to see. I think we had 18
37:15
or so people contribute to the first release
37:17
after initial release or
37:20
sorry the second release of fast UI so
37:22
yeah, good engagement from lots of people. Image.
37:25
You've got a bunch of UI stuff here and
37:28
as I look at this and I see what you're
37:30
building, it just makes me think of like
37:32
wow there's an opportunity for stuff like what
37:35
you get out, not necessarily the same as
37:37
but like what you get out of say
37:40
Tailwind UI where the things you might work
37:42
with are on-off switches, you know like toggles
37:44
like you might see in your phone or
37:46
other sort of elements that have like a
37:49
lot of design imbued in them that people
37:51
can just grab and use almost like a
37:53
Django philosophy for the front end in a
37:55
sense there. Is that something
37:57
that you are dreaming of? Someone
38:00
was complaining somewhere that we didn't have a
38:02
grid component yet and I think we'll do
38:04
one but like those bits get quite Pigninated
38:06
yeah like calendar completely Obvious choice
38:09
right complete fast to go and implement that
38:11
yourself in HTML Commonly used trivial
38:13
to define because because the definition there aren't
38:15
that many different things to define you you
38:17
choose your month You know most of
38:19
us are on the Gregorian calendar, right? We're not
38:21
we're not gonna have to change too much what
38:23
calendar we're gonna render Yeah, that's
38:26
a perfect example of the kind of thing tiles
38:28
like this again Totally possible to
38:30
go and implement them and again obviously you
38:32
can use we can provide some nice people
38:34
but also if you're a bigger company
38:36
and you want to go and Customize
38:38
it you can totally do that and you can
38:40
have a front-end developer go through and implement the
38:43
classes that basically customize Customize the
38:45
look I wanted to come back just and show you
38:47
some of that so that some of the other components
38:49
So we were on yeah, that's why here
38:51
I don't know if we have anything more
38:53
below that but I would love to show
38:55
you that the tables because the tables and
38:57
the Forms of really where it comes into
38:59
cities is probably the best example. Okay. Yeah
39:01
awesome This is a list of cities just
39:03
for some public dataset with country and population
39:06
But at the top you see we have a
39:08
filter to choose my country And if we click
39:11
here if you start searching like UN or something
39:13
you'll see we're doing a server side We're loading
39:15
from the server the list of cities Again
39:18
this component to go and implement if you were
39:20
gonna do that from scratch you've got to have you
39:22
some like clever There's a list
39:24
of countries. So if you do like country, sorry, I've been
39:26
in cities Like you
39:29
and you get United Kingdom in United States. Yeah,
39:31
perfect. There you go And then we do United
39:33
States or whatever Yeah And
39:35
then we'll get a bunch of cities in the
39:37
United States Building this and wiring it all up
39:39
and using one of the we use react select
39:41
here But if you select two or one of
39:44
those components, it's not trivial You need
39:46
to also set up the back end you
39:48
need to set up this there's like a
39:50
few hundred lines of react Dedicated just to
39:52
sit it setting up those those selects correctly
39:54
And as you'll see in a minute on
39:56
a form you can add this to a
39:58
to form with us UI pretty trivially. Secondly,
40:00
if you go to the bottom of the page
40:03
on cities, you'll see pagination. Again, not a trivial
40:05
thing to go and set up if you've got,
40:07
if you're just starting from scratch and you want
40:09
to show like build an internal endpoint, for example,
40:11
to show all of your users doing all that
40:13
pagination and like wiring all that
40:15
up is not trivial, but we effectively do the
40:17
work for you to have that component and do
40:19
the maths of which page you were on and
40:21
stuff like that. I want to reiterate
40:24
this is that fastUI is not just
40:26
designed as a kind of Django admin
40:28
interface alternative. We did pydantic again, we're going
40:30
to go and use it for UI that we're going
40:32
to show to end users, but obviously it also comes
40:35
into its own when people want to just get something
40:37
up quickly. This
40:40
portion of TalkPython to me is brought to you
40:42
by Sentry. You know Sentry for the air monitoring
40:44
service, the one that we use right here at
40:46
TalkPython, but this time I want to
40:48
tell you about a new and free workshop. Heaming
40:51
the Kraken, managing a Python
40:53
monorepo with Sentry. Join
40:55
Salma Alam Neyor, senior developer
40:57
advocate at Sentry and David
40:59
Winterbottom, head of engineering at
41:01
Kraken Technologies, for an inside
41:04
look into how he and his team develop,
41:06
deploy, and maintain a rapidly
41:08
evolving Python monorepo with over 4
41:11
million lines of code that powers
41:13
the Kraken utility platform. In
41:16
this workshop, David will share how his
41:18
department of 500 developers who deploy around
41:20
200 times a day use Sentry
41:23
to reduce noise prioritize issues and
41:25
maintain code quality without relying on
41:27
a dedicated Q&A team. You'll
41:29
learn how to find and fix root
41:31
causes of crashes, ways to prioritize the
41:33
most urgent crashes and errors, and
41:35
tips to streamline your workflow. Join
41:38
them for free on Tuesday, February 27, 2024 at 2 AM civic
41:40
time. Just visit talkbython.fm slash
41:45
sentry dash monorepo. That link is in
41:47
your podcast player show notes. 2 AM
41:50
might be a little early here in the US,
41:53
but go ahead and sign up anyway if you're
41:55
a US listener because I'm sure they'll email you
41:57
about a follow up recording as well. Thank
42:00
you to Sentry for supporting this episode. If
42:05
we have a design language or something like
42:07
that, or even using a framework, I mean
42:09
you mentioned Bootstrap, but Tailwind or Bova, is
42:11
that one of the new ones? Like if
42:14
we're working with one of those and we
42:16
wanted to use this, like how easy is
42:19
it to sort of bring in those elements
42:21
there? So if I show you here on
42:23
Boot, to ask you how we
42:25
customize it with Bootstrap, which is probably the
42:28
best definition of it. So you'll see here,
42:30
this is the, where am I
42:32
looking? This is the pre-built version. So this
42:34
is obviously the pre-built version of FastUI
42:36
you can get, but it's actually just, it's
42:38
a very simple app in terms of React.
42:40
This app has one, well two components. It
42:43
has a div which contains the FastUI component.
42:45
And then we customize it in a bunch
42:47
of ways. We have a component that we
42:49
render for not found. We have a component
42:51
we render for spinner and for transitioning, but
42:53
then these are the two that really matter,
42:55
where we can customize the classes and we
42:58
can customize how we render certain components. So
43:00
if we come in here to have this function
43:02
from Bootstrap, which is how we customize the classes,
43:05
you'll see that at its core, it's
43:07
just this big old switch. So this
43:09
is all TypeScript, like type safe because
43:12
types are very powerful in TypeScript. But like all
43:14
of the props will have this type key, as
43:16
I showed you earlier, when we were looking at
43:18
the Python code. And
43:20
all the different things, yeah. Based on the switch,
43:22
we just go through and this is all just
43:25
like defining the classes we want for all of
43:27
the different components. Some of them depending on the
43:29
exact state of the component. So all of these
43:31
form inputs, we customize them depending on which type
43:33
they are and on which mode we're in, et
43:36
cetera, et cetera. But it's all very mechanical, just
43:38
like laying out the classes we need for each
43:40
individual case. And then
43:42
we have the other way of customizing
43:44
it, which is to use custom components.
43:47
We basically for three in particular components,
43:49
Napa, Modal and Pagination, we
43:51
define our own custom React components. So
43:53
here's the one for Napa, where we
43:56
use a bunch of bootstrap types to
43:58
render a bootstrap Napa. So you
44:00
could basically create a React
44:03
component that has all the
44:05
settings necessary to create an app bar in Tailwind
44:07
or whatever, right? And then just plug that stuff
44:09
in. So if you wanted to use Tailwind, what's
44:11
this, like 20, it's like 100 lines of code
44:14
to define all of the classes. And it's
44:17
pretty mechanical code, right? So it would be,
44:19
it wouldn't be hard at all to go
44:21
and use Tailwind, Tailwind CSS, and
44:23
then you might want to define a few of your
44:25
components specifically. Yeah. But actually, Modal, I
44:27
think, is the only one that really requires it to be
44:29
custom implemented because the default just shows you an alert because
44:32
there's nothing in the script. The
44:35
page says, it's like, oh no, the page doesn't
44:37
say this isn't going to work. Yeah. So
44:39
yeah, I think this is one of the bits
44:41
I'm most proud of here is that like how
44:44
much you could customize it and how simply you
44:46
could start to customize it. Right, those are really
44:48
kind of pluggable or extensible. So you don't have
44:50
to get in and know
44:52
too much about it. You just plug in
44:54
the class name generator and the renderer for
44:56
a specific one. Yeah,
44:59
and all of the types, it's all type scripted. So
45:01
the types should do a lot of help telling you
45:03
what you can implement. Last thing I'll
45:05
show you is, yeah, so here
45:07
in the default builds, as I said, our
45:10
custom render function is not just a
45:12
bootstrap one. We do one special thing,
45:15
which is where we have this idea
45:17
of a custom component, which basically, all
45:19
it has is a subtype, which basically
45:21
you should use to render it however
45:24
you like. So in our case, we
45:26
take custom and if the subtype is
45:28
cow say, we render that as a
45:30
particular block, like use this component here and
45:32
we print out the cow says whatever it
45:35
was that the input was from the server.
45:37
And otherwise, we just go back to using
45:39
the bootstrap render. And so if you look
45:41
at that component here, yeah, it's
45:43
like slightly silly example of a custom
45:45
component of cow say saying something. Oh,
45:47
that's fun. But yeah,
45:49
it shouldn't be too difficult to customize. And then
45:51
even if you're customizing to go back to using
45:54
bootstrap for the full back case of everything else.
45:56
Okay, so you can almost just for one section
45:58
that has to be really specialized. do
46:00
something custom but otherwise just lean on a
46:02
framework. Yeah. Okay. Yeah, this looks like something
46:04
that one person could
46:06
take one for the team, create a
46:08
tailwind or a whatever generator, class name
46:11
generator, and then put that as either
46:13
a contribution or put it up on
46:15
GitHub, and then you're just
46:17
kind of good to go. Yeah, I think
46:19
we might actually do it. We're using tailwind
46:21
and radix within Playdantic, so I suspect our
46:24
frontend guys will at some point get annoyed
46:26
with my use of bootstrap and go off
46:28
and go and change it. One of the
46:30
reasons I use bootstrap is that because bootstrap
46:32
is completely customized via SCSS and
46:34
the SCSS compilers for Python, we have
46:36
the least of possibility in future to
46:38
allow you to customize the complete look
46:41
and feel of your app without ever
46:43
having to touch NPM because you just
46:45
go change basically the color definitions as
46:47
we do here. So
46:49
the default version of, maybe
46:51
I can even change it here and as it's running,
46:53
it'll change. But if I, here you see I've set
46:56
the primary color to be black, and so you'll see
46:58
the buttons here are all rendered as black. If I
47:00
want to change it, I haven't tried this for a
47:02
bit, so I hope it works, comment
47:04
it out primary, you'll see that it all
47:07
changed. The primary, which is
47:09
the bootstrap primary button, dash dash. If I
47:11
changed, I got rid of the default font,
47:13
you would see we went back to whatever
47:15
the other font was. So there's a world
47:17
in future where we allow you to customize
47:19
the look and feel, even within bootstrap from
47:21
Python code. Yeah, tell people maybe who don't
47:24
know what SCSS is. They probably
47:26
know what CSS is. It's generally
47:28
referred to as SAS, which is
47:30
S-A-S-S, which is basically
47:32
a more powerful version of CSS where
47:35
you can... SAS and less, those are
47:37
the two. Yeah, there was SAS and
47:39
less, and then we kind of settled
47:41
on SAS, but then we had SCSS,
47:43
which is SAS with more CSS syntax.
47:46
It's a way to do slightly more
47:48
powerful things in CSS and
47:50
minify it and have stuff like
47:52
variables for they were available in
47:54
CSS and defaults, and even you
47:56
can do weird stuff like map
47:59
functions. they use very heavily in
48:01
bootstrap. But the nice bit is because the
48:03
compiler is written in C, there's
48:05
libsass in Python where you can
48:07
get a front-end customization without leading
48:09
the whole of Node and the
48:11
whole dog and pony show front-end
48:13
development. Yeah, excellent. It's got a
48:15
lot of legs. So when I
48:18
saw this and I saw,
48:20
okay, this is for web amps and
48:22
it's got this Python code running that
48:24
defines the back end, it's got the
48:26
UI and it's all a little self-contained.
48:29
One of the thoughts I had was, wouldn't it
48:31
be neat if there was a little
48:33
bundler type of thing that made this into an
48:35
electron app? Would this be possible? Can we get
48:37
something that you could send out or is this
48:40
really just going to be intended to be a
48:42
friend of Django type of thing? I
48:46
have not used electron for a very long
48:48
time, so I don't pretend to be an
48:50
expert. What I will say is that unlike
48:52
some of the other UI libraries, we're
48:54
not trying to do clever things with web
48:57
sockets and do all
48:59
of the rendering requiring duplex communication between the
49:01
client and the server. It's pretty simple. It's
49:03
like make a request and the JSON contains
49:05
some information about how to render it, and
49:07
then the front-end goes off and renders it.
49:09
So the result what you get when you
49:11
finish is very, in terms of
49:13
from a networking point of view, very simple,
49:15
very conventional. It's like
49:17
make an HTTP request, get back
49:19
JSON JavaScript, knows how to render it. So
49:21
I don't see why it shouldn't
49:24
work in electron. There's even the world in
49:26
which we don't need the whole of electron
49:28
and someone could go and build
49:30
fast UI components for whatever native library,
49:33
and we could get native apps running
49:35
that are based on fast UI. Not
49:37
saying that's necessarily a good idea, but
49:39
those possibilities exist. It does
49:41
exist. Okay. Yeah, very interesting. Another
49:44
thing that is convention, I suppose, I'll see
49:46
if I can pull it out here, is
49:49
that UI a lot of times you'll have
49:51
either just slash or have slash Users,
49:53
but then you'll have an API that backs
49:55
it, And there's this convention that if it's
49:58
in the URL, if you have slash, P
50:00
I saw in this example were like a talk
50:02
about before his eyesight tables are city the B
50:04
C A P I slashed stabilise as the data
50:06
in point and then if you drop the A
50:09
P I at the front end that then turned
50:11
around and cause the back in with her A
50:13
P I inserted right. You wanna talk about back
50:15
to mention a little bits of people can see
50:17
where that's going is about how how I've said
50:20
it up in the diesel and a dog meat.
50:22
you don't have to do it either. Automatic were
50:24
using a separate sub domain to avoid like park
50:26
base booting and all that fun be either the
50:28
the principle that the. Be fooled. simplest way
50:31
of I'd basically doing it. can't keep using
50:33
a calculation to go from of go to
50:35
U R L how do I get a
50:37
date for it is as I said earlier
50:39
as he prepares such a yacht. So maybe
50:41
a more general way to think about it
50:43
is for every page there is an endpoint
50:45
that is a fast ha and point or
50:47
a pair of the maybe even the one
50:49
returns the Html front end stuff that makes
50:51
him look at the talks around and goes
50:53
back to its sell for I guess of
50:56
what we have in the defaults at at
50:58
what I would generally recommend is where up.
51:00
We have a bunch of Brutus that connect
51:02
and do all of the that yeah stuff
51:04
and I've just been implementing or which I
51:06
can tell you a minute but that's not
51:08
available as the Ah for it but it's
51:10
not and what in that semi you're looking
51:12
at a damn We have this like basically
51:14
capsule and Point which is nothing else has
51:16
been hit well rendered to stand in html
51:18
than. One of the nice things is that
51:20
that I could migrate give you this prevail
51:23
html which will basically Wendy's of He when
51:25
you get him out with your cat if
51:27
you I I went here on a deep
51:29
a source. You say just hundred idea?
51:31
Which are them Lock Yeah this particular I
51:33
went eight thousand that it wouldn't be messed
51:35
up by beats you just as if by
51:38
simple Html which in turn meant as the
51:40
So yeah you're right. This to the sewer
51:42
is like matching and points for read reviews.
51:44
You might want to have one two separate.
51:47
as a Jason the wanted to get him
51:49
out but you don't write. Write them both
51:51
right. You're right that a P I won
51:53
and then fast you I magically certain hundred
51:56
ninety you. I write whatever. we're this with
51:58
all of my service. That's another
52:00
form submission would all just walk out
52:02
the box with with any point in
52:04
web framework you just need to produce
52:06
your financing model number to Jason and
52:08
button that as in a response. The
52:10
one of the really nice things about
52:12
that just being there like actual data
52:14
with existing Nj Saudis that met writing
52:16
a test is quite low head of
52:18
the but you'll see most of it
52:20
is is marked outside writing a test
52:22
the are these can table expect them
52:24
to is massively the along attacking against
52:26
Jason which we can provide an item
52:28
objects and test then. It would be if
52:31
we got a demo page were running a
52:33
bunch of projects is that does this page
52:35
contains the use his name? Does it contain
52:37
the Wedlock out blah blah blah yeah I
52:39
buy our right type of are.those I said
52:41
Tessa school yet and even worse you end
52:43
up with that favourite and like and playwright
52:45
the image of it and see the images
52:47
are images to luck and yeah things I
52:49
don't want to have to go away with
52:51
that happen again need but I were an
52:53
ironic it will probably end up with them
52:56
in sauce you I'd say like even more
52:58
certainty that accompanies what correctly but I see.
53:00
That that by Floyd everyone else having sex
53:02
scandal? Is there any concern that maybe there's
53:04
unintended A P eyes in the sense that
53:06
like all of the stuff and so the
53:09
supply true for pretty much any rat's cage
53:11
And besides, but like a lot of the
53:13
page is available also isn't a P I
53:15
even if you don't intended to be in
53:18
a P I like what's yeah, that's a
53:20
limitation of any minute. some ways that they
53:22
too will be slightly less nice to. Yeah,
53:24
you're If you're at a company the get
53:26
people foreign exchange rates and you want them
53:29
to Boys comes. your sights you obviously top
53:31
end of that with with react as the
53:33
set of a decimal point where someone could
53:35
discuss spread your exchange rates or whatever other
53:38
i try but you can still do session
53:40
based off and say you have to log
53:42
in to do it right is not just
53:44
that it's public it just yet there's always
53:46
a jason version but honestly there's so many
53:49
interesting ways to pull data out of html
53:51
like yeah some of must have a right
53:53
audible i'm a mother anyway i also think
53:55
that like in theory it's your options are
53:58
built here react or do this and This
54:00
has the, as I say, the realistic
54:02
job. Someone's going to come along and
54:04
implement a fast UI front end that
54:07
renders HTML and then you don't have
54:09
to expose those JSON endpoints at all
54:11
and you could return HTML from your
54:13
server. We just haven't got around to building
54:16
it yet. Yeah. I guess you could
54:18
maybe do some kind of server-side rendering potentially as well.
54:20
Exactly. That's what I mean. Whether
54:22
it's Python server-side rendering or whether it's JavaScript
54:24
server-side rendering or whether it's edge rendering. I
54:26
tried to build the edge rendering thing in
54:28
Cloudflare years ago using Rust and for a
54:31
bunch of reasons it didn't quite work but there's
54:33
real possibility of doing any number of different things
54:35
in that direction. That's interesting. Some
54:37
of the CDNs have pretty dynamic stuff right
54:40
at the edge where you can put your
54:42
last bit of code. I haven't done anything
54:44
with that. That's what Remix is doing and
54:46
Next.js to a lesser extent. In
54:49
theory, maybe I'm overblowing it
54:51
and fastUI will remain
54:53
what it is now but in
54:55
theory, we've set up this language
54:58
of different components that hopefully is,
55:00
whilst by no means universal, complete
55:03
enough that you can build lots of common user
55:05
interfaces with it and then if you really gained
55:07
adoption, then people can go build new backends and
55:09
new frontends and they all in theory should be
55:11
able to mix and match with each other. We'll
55:13
see if that happens. Yeah. Widgets
55:16
too. I see it tell when UI
55:18
created a paid thing for higher
55:20
order widgets potentially. Just being
55:22
React already makes that. That probably exists and I
55:25
just don't know. There's been a number
55:27
of issues of people wanting to render
55:29
existing, basically build extensions to
55:31
fastUI to render their widgets. I think we
55:33
will probably support the rep for HTML that
55:36
things like pandas data frames already return so
55:38
that you could, for example, return a data
55:40
frame and it might not be pretty but
55:42
you'll get something coming up as HTML and
55:44
start ugly and then move on to doing
55:47
those things in an even more powerful way.
55:49
Sure. Yeah, I didn't even
55:51
think of a data science side but there's probably
55:53
a lot of cool dashboard widgets connected to pandas
55:55
and pullers that are potential out there. Yeah, and
55:57
charts and visualizing data is something I don't think
55:59
it's possible. is interested in, there's no reason
56:01
why a lot of them couldn't be
56:03
implemented as fast UI components and then
56:05
displaced. Okay, we are running pretty short
56:07
on time. I feel like we should
56:09
probably bring a little more pedantic to
56:11
the side and just talk real quickly
56:13
about forms, right? What do you think?
56:15
Yeah, absolutely. So if you probably use
56:17
this, if you share, let me see,
56:19
share my screen, I'll do it from
56:22
here because I can also, it's like
56:24
the full behind the scenes. Yeah, yeah,
56:26
it's probably most interesting if we look
56:28
at the how the form is implemented
56:30
in the code first and then we look at what
56:32
that means for the UI. So this is the login
56:34
form that Michael you were just showing here that I
56:36
can show, which is the login form with an email
56:39
address, password, some validation, basically like
56:41
that. That's powered entirely by, again,
56:43
a completely vanilla pedantic model. And
56:46
the way that we return that is we
56:48
return three things, heading,
56:50
which is like just telling a person what
56:53
we're looking at here in the demo. And
56:55
then the third thing is that it's interesting
56:57
bit where again, actually, the model form is
56:59
again, generic around the pedantic model. And then
57:01
it takes one other argument, which is the
57:03
submit URL. And that's enough information. Right. So
57:05
what you're returning as part of that hierarchy
57:07
in Python is a model
57:09
form and you give it a pedantic
57:11
model. And so it looks at the
57:13
pedantic class and says, we're going to
57:15
create like an email address and a
57:17
password field and so on, right? Exactly
57:19
that. Awesome. Okay. So
57:22
when you submit that form, it's
57:24
submitted as form data. So is
57:26
it not as JSON data, but
57:28
as a vanilla HTML form? A
57:30
standard form, post type of thing. Post form.
57:32
And then we have this, it's
57:35
this syntax is definitely slightly funky here, but it's
57:37
how we do it in fast API.
57:39
We have form, which is annotated as
57:41
a login form, but it's also got
57:43
fast UI form, which in turn, which
57:46
also takes login form, all of which
57:48
looks a bit ugly. But what we're
57:50
really doing in the background is converting
57:52
form data into the pedantic model, including
57:54
flattening and the flattening the model in
57:56
the case where we have nested models,
57:58
which I'll show you. in a minute.
58:00
But the result of this is once we
58:02
in our post-endpoint, we get an instance of
58:04
the login form that we can then go
58:06
do stuff with. If I show you a
58:09
more comprehensive or complex example, this big
58:11
model here becomes big form and this has
58:13
a bunch more stuff in it. So it
58:16
has file inputs. Now file inputs are one
58:18
of the reasons we can't just submit JSON
58:21
because they can be very, very large. Yeah,
58:23
they can be the most important part in coding and all those
58:25
things. Right. And
58:27
so here we have name. We use
58:30
bold again as I have before to
58:32
indicate required fields. So we could, I
58:34
don't know, have got some pedantic logos
58:36
here that I'll use images.
58:39
This one is multiple images. So we
58:41
can select multiple images. A date field
58:43
in this is date. I've got a
58:45
calendar picker. Very nice. Is that just
58:47
input type equals? That's just input type
58:49
equals date. Okay. We have switches. We
58:51
have, and then you'll see here we
58:54
have size model, arrow width, size model,
58:56
arrow height. And the point is that
58:58
we're doing here, and these are integer
59:00
fields, but the cool bit is that
59:02
they map to a nested pedantic model
59:04
within the big model. Okay. What fastUI
59:06
is doing internally is basically flattening this
59:08
into one list of form fields, which
59:11
is then what we get rendered here.
59:13
I see. So in your pedantic model,
59:15
you have a size up object, but
59:17
then in the form, it just has
59:19
the width and the height one after
59:21
another. Yeah, width and size height. Exactly
59:23
that. If I put a requirement or
59:26
a restriction like min or max onto
59:28
the field in the size model, will
59:30
that become a client side min and max in
59:32
the form? There's an open PR to do exactly
59:34
that. Awesome. Yeah, we will do it, but obviously,
59:36
we will get server side validation as well. And
59:38
then we will get it for a couple of
59:40
weeks. So like it's, there's
59:43
more to do, right? But that's awesome. That'll be fun.
59:45
And then you'll see in uploads, we have some quite
59:47
powerful things we can do here. So we
59:49
use the upload file, which is a
59:52
start-up type, but we can also annotate
59:54
it with form file, which Takes
59:57
two optional arguments of what rule,
59:59
what accept. To apply so that
1:00:01
will both in the brow the when you
1:00:03
open the i owe you choose a file
1:00:05
browser dialogue and it'll tell me whether I
1:00:07
observed for people as he of the mime
1:00:09
type set not like of extension be of
1:00:11
image/star which means you know I'm as I
1:00:13
say peg Png web t et cetera right
1:00:15
But and that's undertaken by the browser and
1:00:17
then by the and then by the off
1:00:20
to some at you select files but it's
1:00:22
also validated server side so if someone goes
1:00:24
in at a search Tim Allen submits and
1:00:26
not image the service I population will check
1:00:28
at least based on the five extension. That
1:00:30
it that it looks like an image and I'm
1:00:32
you get back the fights So you could also
1:00:34
go to validation that the bites are about it
1:00:37
image if he if he signs it can read
1:00:39
the bomb the of the mark that indicates the
1:00:41
file type that sometimes in these different files. yeah
1:00:43
if I submit this but that's a buffer to
1:00:45
her transmit this because we don't satisfy both a
1:00:48
sinner which fields of acquired it will let me
1:00:50
submit assists. Five failed is not completed and then
1:00:52
I think if we put a name and we
1:00:54
don't capitalize it in this case will go off
1:00:56
and do the validation and come back and will
1:00:59
say name is start. With a capital with
1:01:01
I've implemented at where's that validation oh
1:01:03
I see the tab a function that
1:01:05
you right but suggested to prove a
1:01:07
point I've just written about a data
1:01:09
in and pedantic would says business thought
1:01:11
with with uppercase and som. If I
1:01:13
then went to hear an edited that's
1:01:15
without form the in the now clear
1:01:18
my full night's know which is magic
1:01:20
If I submit that you'll see here
1:01:22
where I printed out the form we
1:01:24
got there we got we didn't file
1:01:26
objects and we got the road Beta
1:01:28
or Cancer as a financing down. that's
1:01:30
really cool and so i love how
1:01:32
even the custom validators and pedantic like
1:01:34
python code that you wrote appears on
1:01:37
what feels like client side but israelis
1:01:39
server side validation run by your yeah
1:01:41
thrive yeah exactly that the sensible do
1:01:43
stuff like lake jackson over things you
1:01:45
can do have input client side as
1:01:47
well but of course that also be
1:01:50
be enforced set aside which obviously to
1:01:52
bogey anything that you gonna be exposed
1:01:54
to upset you gotta take yeah you
1:01:56
should never never trust on comes into
1:01:58
your web app as just put
1:02:00
it online for five minutes and look at
1:02:03
the log. It's already trying, somebody's already after
1:02:05
WP admin.php, you know? Yeah, exactly that. And
1:02:07
then the last thing I'll show, I know
1:02:09
we haven't got very long at all, is
1:02:11
authentication, which I've just been working on now.
1:02:14
This is, again, this is a simple form. I'm
1:02:16
just gonna select an email, put in the random
1:02:18
passwords, and I can log in. And
1:02:21
in this case, I've logged it, it just says who
1:02:23
I am and how many people are logged in. If
1:02:25
I come back to this page, it'll show me logged
1:02:27
in, and I can do post requests to log out.
1:02:29
And what it's doing internally is, and
1:02:32
again, this is the kind of thing that would
1:02:34
be lots and lots of work to implement if
1:02:36
you're doing it yourself, is it storing in session
1:02:39
storage, the auth token, then adding it as a
1:02:41
header, where we do the fetch from the front
1:02:43
end to the back end, so we can effectively
1:02:45
store sessions that way. Oh yeah, very cool. Yeah,
1:02:47
all tokens coming in as a header item are
1:02:50
being set as a header item, excellent. Right, exactly.
1:02:52
Cool. So yeah, I hope that
1:02:54
we've done a bit of a whirlwind tour
1:02:56
through FastUI and what's there now, and what
1:02:58
I hope is coming up, the slightly faux-loss
1:03:00
of how, why I built it. But yeah,
1:03:02
I think that was interesting. It's super interesting,
1:03:04
and it's really early days. I'm
1:03:07
looking forward to two things, to see what
1:03:09
people go do with it, what widgets and
1:03:11
stuff they build, so can you drop in,
1:03:13
like you said, a calendar or something awesome
1:03:15
like that. And I'm also looking forward to
1:03:17
see what you all internally release in a
1:03:20
couple months from it. Absolutely, yeah, thanks so
1:03:22
much for having me and
1:03:24
letting me witter on about this
1:03:26
random library. Yeah, of course, good
1:03:28
work. It's certainly creative. Maybe
1:03:30
just give people a sense of, as
1:03:33
we wrap it up, can they use
1:03:35
it now? Should they use it now?
1:03:37
Can they contribute? Maybe they're interested. What
1:03:39
do you tell that crew? I'd love
1:03:41
people to contribute both, I mean, almost
1:03:43
most useful is issues saying how you're
1:03:45
using it, where it's working, where it's
1:03:47
not. There is a bunch of people
1:03:49
who've already submitted PRs and continue to
1:03:51
do so. And yeah, I think what
1:03:53
works, works pretty rigorously, and it's probably
1:03:55
better implemented and tested in lots of
1:03:57
like private code, but definitely within... internal
1:04:00
uses use it now and like I say,
1:04:02
pedantic is building things with it
1:04:04
now. So look, I mean, I give
1:04:07
the open source guarantee that it's relatively
1:04:09
safe, which is the guarantee that means
1:04:11
nothing. But mostly because at the
1:04:13
end, it's just defining how you build your
1:04:15
UI and how you implement your session authentication.
1:04:18
It's not having strong opinions about that. So
1:04:20
yeah, I think it's the place where people
1:04:22
should go and try it and give
1:04:25
feedback. Excellent. All right, well, thanks again
1:04:27
for coming on the show. Looking forward to talking to you next
1:04:29
week. No, just kidding. Like 200 rows. Looking
1:04:31
forward to talking to you 2024. Absolutely. Have
1:04:33
a good Christmas. Thank you so much. Yeah, thanks.
1:04:36
Bye. This has been another episode of TalkPython
1:04:38
to Me. Thank you to our
1:04:40
sponsors. Be sure to check out what they're offering. It
1:04:43
really helps support the show. Bright
1:04:45
Data is professional web scraping in a
1:04:48
dataset marketplace. If you need data and
1:04:50
it doesn't have an API, check
1:04:53
out talkpython.fm slash Bright Data
1:04:55
today. Take
1:04:58
some stress out of your life. Get
1:05:00
notified immediately about errors and performance issues
1:05:02
in your web or mobile applications with
1:05:04
Sentry. Just visit talkpython.fm slash
1:05:07
Sentry and get started for free.
1:05:09
And be sure to use the
1:05:11
promo code talkpython, all one word.
1:05:15
Want to level up your Python? We have
1:05:17
one of the largest catalogs of Python video
1:05:19
courses over at TalkPython. Our content
1:05:21
ranges from true beginners to deeply advanced
1:05:23
topics like memory and async. And best
1:05:25
of all, there's not a subscription in
1:05:28
sight. Check it out for yourself at
1:05:30
training.talkpython.fm. Be sure to
1:05:32
subscribe to the show, open your favorite podcast app
1:05:34
and search for Python. We should be right at
1:05:36
the top. You can also find
1:05:39
the iTunes feed at slash iTunes, the
1:05:41
Google Play feed at slash Play and
1:05:43
the direct RSS feed at slash RSS
1:05:45
on talkpython.fm. We're live
1:05:47
streaming most of our recordings these days. If
1:05:50
you want to be part of the show
1:05:52
and have your comments featured on the air,
1:05:54
be sure to subscribe to our YouTube channel
1:05:56
at talkpython.fm slash YouTube. This
1:05:58
is your host, Michael Kennedy. Thanks so much
1:06:00
for listening. I really appreciate it. Now get out there
1:06:02
and write some Python code.
Podchaser is the ultimate destination for podcast data, search, and discovery. Learn More