Podchaser Logo
Home
Building UIs in Python with FastUI

Building UIs in Python with FastUI

Released Tuesday, 13th February 2024
Good episode? Give it some love!
Building UIs in Python with FastUI

Building UIs in Python with FastUI

Building UIs in Python with FastUI

Building UIs in Python with FastUI

Tuesday, 13th February 2024
Good episode? Give it some love!
Rate Episode

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.

Unlock more with Podchaser Pro

  • Audience Insights
  • Contact Information
  • Demographics
  • Charts
  • Sponsor History
  • and More!
Pro Features