Learn Python with Talk Python's 270 hours of courses

#449: Building UIs in Python with FastUI Transcript

Recorded on Monday, Jan 8, 2024.

00:00 Building web UIs in Python has always been an interesting proposition.

00:04 On one end, we have the full web design story with artisanal HTML and CSS.

00:09 On the other end, there are several Python platforms that aim to bring RAD, Rapid Application

00:15 Development style of building Python apps to the web.

00:19 Those can be great, and I've covered a couple of them, but they usually reach a limit on

00:23 what you can do or how they integrate with the larger web ecosystem.

00:28 On this episode, we have Samuel Colvin back to share his latest exciting project, Fast

00:33 UI.

00:34 With Fast UI, you can build responsive web applications using React without writing a

00:39 single line of JavaScript or touching NPM.

00:42 Yet designers and other tools can focus on React front ends for a professional spa-like

00:48 app experience.

00:50 This is Talk Python to Me, episode 449, recorded December 14th, 2023.

00:55 Welcome to Talk Python to Me, a weekly podcast on Python.

01:13 This is your host, Michael Kennedy.

01:15 Follow me on Mastodon, where I'm @mkennedy, and follow the podcast using @talkpython,

01:20 both on fosstodon.org.

01:22 Keep up with the show and listen to over seven years of past episodes at talkpython.fm.

01:28 We've started streaming most of our episodes live on YouTube.

01:31 Subscribe to our YouTube channel over at talkpython.fm/youtube to get notified about upcoming shows and be

01:37 part of that episode.

01:40 This episode is sponsored by Bright Data.

01:43 Bright Data is professional web scraping and a dataset marketplace.

01:47 If you need data and it doesn't have an API, check out talkpython.fm/brightdata today.

01:54 And it's brought to you by Sentry.

01:57 Don't let those errors go unnoticed.

01:58 Use Sentry like we do here at Talk Python.

02:01 Sign up at talkpython.fm/sentry.

02:02 Hey, Samuel, welcome back to Talk Python to Me.

02:08 - Thank you.

02:09 Thank you very much for having me again.

02:10 So soon after last time.

02:11 - It's always amazing to have you on.

02:13 In fact, you were on just last week in a really cool show that tons of people enjoyed and

02:20 is not yet out at the time of recording, but will be released to the world by the time

02:24 your show goes out live.

02:25 So it's a bit of a time travel thing.

02:28 Very, very appropriate here.

02:29 But it was under the full-time open source developers panel of like a bunch of folks.

02:35 For example, Charlie Marsh, Will McGugan, Gina Houska, and so on.

02:40 And you snuck in for a minute there on your travels, but now you're back and we're here

02:46 to talk properly about something really excellent that you put together called Fast UI, which

02:52 is gonna be a lot of fun.

02:53 - Yeah, thanks so much for having me.

02:55 And yeah, I'm in a slightly better environment for a podcast than the stairwell of a restaurant

03:02 somewhere in Istanbul.

03:03 So yeah, it's nice to be here.

03:05 - High marks for effort there.

03:06 Come on, that was great.

03:08 - It was good fun, but this is a better place to talk about these things.

03:12 - Yeah, well, I hope you had a good trip and you're back and at it.

03:16 Kim out in the audience points out, "Hey, could you just write another impressive tool

03:18 for the next week's show?

03:20 'Cause things are going pretty prolifically over there." You tell people a bit about Pydantic, the company, they probably heard of the library,

03:27 but just what are you up to these days?

03:29 - So Pydantic's obviously been around since 2017 originally, but then it's like something

03:34 weird happened at the beginning of 2021.

03:36 I don't know quite what that was, but Pydantic, the downloads just went crazy.

03:40 So we were at like 5 million downloads then and we're now at 130 million.

03:44 So yeah, it's gone crazy.

03:46 And then just a bit more than a year ago, I was very lucky.

03:49 Sequoia got in touch with me and basically said that I want to start a company.

03:53 I had been meaning to do that after I released Pydantic V2 that I was then working on.

03:58 Yeah, I started the company beginning of this year and now have an amazing team of 10 people

04:03 working with me.

04:04 So we released Pydantic V2 finally, having originally told people it would take me alone

04:08 three months.

04:09 It took me and I guess then six people a year in total, but that was released back in the

04:14 summer and now we're working on a platform that I'm not going to talk about now, but

04:19 I would love it if you'd have me back, I guess, beginning of Q2.

04:23 - Is that next week or whatever?

04:24 - It's not quite next week.

04:25 - Q2 2024, something like that?

04:26 - Yeah.

04:27 - Okay.

04:28 - I think we're going to try and get to open beta in Q1.

04:32 So yeah.

04:33 - Okay, fantastic.

04:34 Yeah, well.

04:35 - But off the back of, so that without getting into a lot of details on it, has platform

04:40 components to it.

04:41 And so we have people, people will be logging in, et cetera, et cetera.

04:45 And I was just thinking about all of the path and the churn of building the relatively mechanical

04:50 bits of an application again, with, it doesn't matter actually if you're building it with

04:54 React or with one of the other front end frameworks, you end up having a whole bunch of stuff that's

04:58 duplicated between what the front end guys are doing and what the full stack developers

05:03 or the backend developers are building for us.

05:06 And I guess for lots of people, there's a pydantic model that's kind of at the core

05:08 of lots of those bits.

05:10 And I was just dreading all of that churn.

05:12 And I had been wanting to build something like FastUI for a long time, but the fact

05:16 that we're going to be using it internally really spurred me on to go and get it built

05:20 and release it in a very incomplete phase to see what people thought.

05:24 And yeah, there's been a great reaction and here I am.

05:26 - Yeah, there has been quite the reaction to it.

05:29 Let's see, do the GitHub star test.

05:32 It's 2.6 thousand stars and it's what, two weeks old?

05:37 A month old?

05:38 Yeah, a month old.

05:39 Last month anyway.

05:40 - Well, it was only released publicly like, yeah, two weeks, it left them two weeks ago.

05:43 Or maybe two weeks ago today.

05:45 - Oh, that's right.

05:46 Yeah, you probably, so you worked on it a little bit private and then you flipped the

05:49 bit on the public status.

05:50 Yeah, that makes a lot of sense.

05:52 Because you don't want people just to go, "Whoa, what are they building?"

05:55 Maybe you do.

05:56 Maybe you're like, "What is this GitHub repo?" They misspelled FastAPI.

05:59 I don't know what they're working on.

06:01 - Yeah, exactly.

06:02 And also, I mean, we have a team with lots of people who've done lots of open source,

06:06 very strongly opinionated engineers.

06:08 I can't even get my team to use it without kind of proving the value in it.

06:12 So I worked on it a bit without really talking to them and then was like, "Right, I built

06:15 this thing, let's at least give it a try." I don't know, maybe I'm wrong in this, but I think it's quite a fundamentally different

06:23 way of thinking about how you build user interfaces from lots of the tools that exist today in

06:29 the Python ecosystem.

06:30 And so there's a bit of a like education piece and trying to understand the principle as

06:34 well as the like mechanics of going and using it.

06:37 - Yeah, absolutely.

06:38 Well, we're gonna dive into the philosophy, but I'll give people the too long, didn't

06:43 read version.

06:44 Basically, you can create UIs in pure Python in sort of dynamic web framework friendly

06:49 ways, right?

06:51 - Yeah, probably the mistake is in my description of it because yes, it does that.

06:55 But where I personally think FastUI is powerful and where we're using it within the Pydantic

07:01 team is actually, we have got front-end developers, we've got some really expert guys who are

07:06 very comfortable building stuff in React.

07:08 But we want those two roles to have to constantly communicate to build every individual bit.

07:14 So the idea is, I think if you go down the page a little bit, I kind of explained it.

07:18 But like for a Python developer, it's this way of building UIs without having to touch

07:22 TypeScript or JavaScript or NPM or any of those Byzantine like massive build tools.

07:29 But then for a front-end developer, it's this opportunity to go and build the best components

07:32 you can and allow, basically provide a powerful interface for your backend guys to go and

07:38 build a UI with it.

07:40 So kind of split those two things up and I guess allow React to do what React does brilliantly,

07:45 which is provide these like reusable components.

07:47 - Yeah, absolutely.

07:49 Kind of a framework as well to bring the navigation and the cohesion of the whole app together,

07:54 not just a particular view or a page too, you would say, right?

07:57 - Yeah, so the weird bit is principle of RESTful interfaces.

08:01 We've all heard of REST or RESTful and we all think we know what it means, which is

08:03 basically something to do with a URL structure and return me some JSON that like gives me

08:09 the data I need to render my view.

08:11 Well, if you look at the Roy Fielding's original PhD, as is brilliantly described in this HTMX

08:17 article that I talk about further on down here, he's not really talking about that stuff.

08:21 Sure, he has some stuff on what the URL structure should be, but really his principle is that

08:26 the data returned from the backend should be self-describing as if it should have everything

08:32 you need to go and render the user interface.

08:34 So let's say, I think they're using the HTMX example, example of like a bank account.

08:39 And if you go down to like principle, the long version, here we are, right?

08:43 I've linked to the PhD, but more importantly, the HTMX article, which explains it really

08:47 well.

08:48 I think if we follow that, yeah, I think they'll even on that page, there's a very jokey tone

08:52 lots of the time HTMX, but they also have a really cool thing.

08:55 - Yeah, absolutely.

08:56 - Somewhere I think they have, yeah, here we are, right?

08:58 So if you look at the traditional JSON response, which I think is the second one, and you were

09:02 trying to show, yeah, right.

09:03 So this, you and I as humans can read this and be like, yeah, that kind of explains my

09:07 bank account and what's going on.

09:09 But there was not enough-

09:10 - Right, it's got like an account number and a balance, which is a more complicated object,

09:13 nested objects and those types of things.

09:15 - Right, it's got all the things that we can read account number, cool, that's a number

09:18 balance, yeah, that makes sense.

09:20 But if you're a computer, there's not enough there to go and render someone the nice user

09:23 interface they would want where they would have it displayed on a page.

09:26 So if you were the engineering team in the bank trying to turn this into a web interface,

09:33 you then need to go and have lots of very application specific or page specific logic

09:38 to show where the account number goes and where the balance goes and where the status

09:41 goes and stuff like that.

09:42 And that causes enormous amounts of churn and it means that it's particularly difficult

09:46 when you have those engineers working at different time zones because you end up having this

09:50 spec between the two.

09:51 And then you always have this problem with software where, fine, we can get it to work,

09:55 but what happens when we come to add it?

09:57 So what's the process of, let's say we want to show as well on this page, your like joint

10:02 account balance, let's say, just to make something up.

10:04 What we probably need to do is we need to get backend guys to go and add that to end

10:09 point and then the front end and that can be deployed and then the front end can be

10:13 updated to show that and the data is available.

10:15 That is a lots of churn, lots of delay in that.

10:18 Right.

10:19 Lots of coordination between the two domain experts and then it kind of, you got that

10:23 microservice cascading, like it's got to do, then this one's got to be upgraded.

10:28 And then eventually there's enough flow of data through the system that the UI people

10:31 can put it up there, right?

10:33 Right.

10:34 And so, and it's bad in this case of like showing your bank balance, but it gets even

10:38 worse when you have a pool where every field in the form needs to be, needs to be completed,

10:43 for example.

10:44 And so we basically have to deploy the front end that has all of the form components and

10:48 the backend that receives that new form at the same time.

10:52 And we've got this piloting model that, you know, depending on how we've done it probably

10:56 is used to define our form and it might even be used to define our database.

10:59 But like we're not using a piloting model in the front end TypeScript, in my opinion,

11:04 the big Achilles heel in typing is that you don't have any, you can't use type in at runtime.

11:09 And so we don't have an equivalent of I'd answer it.

11:12 And so we're basically trusting that data is how it is.

11:15 So yeah, FastAPI is a, is an attempt, sorry, fast UI is an attempt to basically remove

11:19 that need to like have complete synchronization between backend and front end by having beautifully

11:25 designed components in the front end.

11:28 Not saying what we have now is that beautiful, but that's the idea long term.

11:31 But then the backend can basically just do the orchestration can say, show me a table,

11:35 show me a form, show me a modal and put the following content in it, et cetera.

11:40 Excellent.

11:41 Nice comment from Tony on the audience says I originally started in Python and went to

11:44 using TypeScript.

11:45 Pydantic made the transition back to Python so nice.

11:49 And so in your description, you also have up here that this Pydantic is interesting,

11:54 is involved here.

11:55 Like what is the role that Pydantic plays in defining all this?

11:58 So the idea is that we're getting to have this restful UI is really that we, we end

12:04 up having a bunch of components in a shared definition of some components.

12:09 And we basically promise that the backend is going to send data that matches the types

12:13 defined in the front end.

12:15 That's all very well, but if you're not careful, you end up not sending quite the right data.

12:19 So what's nice is that all of the components that you can return from fast UI are themselves

12:25 Pydantic models.

12:26 So Pydantic goes off and does not only the validation, but also the coercion and it does

12:31 stuff like uses camel case.

12:33 So the front end developers are happy because we've got every no underscores anywhere.

12:37 And so yeah, the, all of the front end, sorry, the backend code for fast UI is basically,

12:43 it's just Pydantic models, which, which implement these components.

12:46 Right.

12:47 So it might be useful for those who can't see this to go in and I can talk through an

12:50 example if we go into the code here and I can talk you through like a very basic component.

12:55 Oh, maybe it'd be, I showed it here.

12:57 So I've got, got the code base open here, just working on something.

13:02 But if I open up here, source and then the Python package, and then we look into components

13:08 and we can look at like a really simple component, probably a button, which would be kind of

13:13 understandable to everyone.

13:14 Where's button?

13:15 Here we are.

13:16 So this is just a plain Pydantic model, which contains text, which is the text you would

13:20 put within the button.

13:21 Then it contains the event that you want to fire when someone clicks on it and HTML type,

13:27 which matches what you can get in HTML, button, reset, submits, and then class name, which

13:33 becomes the classes that get applied.

13:35 And then critically this type, which is a literal, which has to be button.

13:39 And that is used by the discriminated union in Pydantic to do the validation of different

13:45 types.

13:46 And it's also used by a big switch statement in the, in the TypeScripts to basically decide

13:51 what component I'll go and render when I, when I get an object.

13:54 Right.

13:55 So there's some TypeScript, maybe it makes sense to talk a bit about the building blocks.

14:01 So you say FastUI is made up of four things just so people can get a sense of like, you

14:06 know, what's at play here.

14:07 Right.

14:08 So, so the four things that we have now package a Python package called FastUI, which I was

14:12 just showing you there, the types for, and then we have NPM package called FastUI again,

14:18 it's in the Pydantic organization, which is where the meat of the, of the logic resides.

14:23 And that's, that's implementing basically the most of the components and all of the,

14:29 the wiring to mean that when I return a button, a button, the button component gets, gets

14:33 rendered.

14:34 And then, but obviously we don't probably want to end up using a vanilla button when

14:38 we come to display it.

14:40 So then I've implemented basic customization of the FastUI React library using Bootstrap.

14:46 And all that's really doing is it's deciding what classes to append to use with each component

14:50 and also just customizing a few of them.

14:52 So for example, modal, there's no like nice way to do a vanilla modal.

14:56 So the modal implementation in the default FastUI package just basically shows me alert

15:01 saying this isn't implemented.

15:02 Whereas the Bootstrap one uses a nice Bootstrap modal.

15:05 And then we have finally FastUI prebuilt, which basically uses the FastUI package, customizes

15:11 it with FastUI Bootstrap and then, and then builds it.

15:14 And that means we can, we can go and basically return that prebuilt React app without having

15:19 to get our hands dirty with NPM on yarn and all the other.

15:24 All the web packy bundling minifying transpiling business.

15:29 But the cool bit, in my opinion of FastUI is that at its core, it's really the definition

15:34 of a bunch of different schemas effectively.

15:36 Those schemas are defined in Pydantic and they're defined in TypeScript, but they could

15:41 perfectly well be, and really nicely, I just merged it the other day.

15:45 We now use the JSON schema generated by Pydantic and JSON schema generated by the React types

15:52 to basically go and test that there's an equivalence between those two, those models everywhere.

15:57 But in theory, there's nothing to stop the front end from being built with another JavaScript

16:01 library or even, even with something like HTML and HTMX, or even you could go and use

16:06 React Native and builds, or even some kind of embedded device.

16:09 You could go and implement those components.

16:11 And then on the other side, and this is even more achievable, you could go and return data

16:16 that matches those models from a Rust or Go service.

16:21 And in theory, not have to change your UI at all, because all you're doing is I promise

16:24 that I'm going to match these schemas and then whatever front end and whatever back

16:29 end can then communicate.

16:31 Whether that comes to pass, I don't know yet.

16:32 And obviously I built the default backend in Python, because that's what I know best

16:36 and where I think Pydantic is really helpful and I built the first front end in React and

16:42 TypeScript because one, that's what I know.

16:43 And two, it's what we're using within Pydantic.

16:45 But there's a, you asked, lots of people have asked about HTMX.

16:48 People have also asked about Svelte and others.

16:50 I think I wouldn't see the point in building like fast UI in Vue because I don't think

16:55 it adds much.

16:56 It's just a lot of work.

16:57 But I think there's a world where we build a HTMX template rendered version of fast UI's

17:03 front end that could be super valuable.

17:05 That's interesting.

17:06 So first point is these different components sound like they are potentially a little mix

17:11 and match.

17:12 You know, you could take it all as one big thing, or you could say really like the way

17:15 it defines the React front end, but we're going to implement it some other end point.

17:20 Yeah.

17:21 I think it's something like, it'll be slightly skewed now because of tests, but I'd say it's

17:25 sort of twice as much front end to backend at the moment as in the, yeah, it's skewed

17:30 a bit by test, but even now there's more TypeScript.

17:33 So I think the simplest thing to do, and you could do it pretty trivially, would be to

17:37 use another backend, another language for your backend service.

17:42 And as long as it matches those types, and you could even go and use something like JSON

17:45 Schema to enforce that.

17:47 But yeah, re-implementing the front end, probably a bigger piece of work, but totally doable.

17:51 I mean, I did it in my spare time in two weeks, built the whole thing.

17:54 So it's not, you know, millions of different things.

17:56 There's kind of 20 components at the moment that are then composable to build reasonably

18:00 sophisticated like UIs.

18:02 So this is a web front end like Flask or Django sort of framework, but a way that really incorporates

18:09 building the UI in Python and validating and enforcing that with Pydantic rather than just,

18:15 Hey, file new HTML.

18:17 Let's just start typing and hope they line up, you know, like instead of trying to juggle

18:21 all those different languages, CSS, HTML, all the JavaScript tooling for packing up

18:26 stuff, just let's write Python, right?

18:29 So maybe you got a simple example of what it looks like to define a real simple example

18:35 here on the readme.

18:37 It's got a very interesting parity between what is in the HTML DOM and is what is in

18:44 the Python abstract syntax tree, I guess, right?

18:49 And visually as well, the way you look at the code, it looks like the way it might look

18:53 in HTML.

18:54 Like give us a sense of what writing a UI in this would look like.

18:57 Right.

18:58 So I think the first of all, we have to talk about like the two enormous, the two most

19:01 obvious pitfalls for this.

19:03 One end of the pitfall you have, which I think is the biggest temptation is to basically

19:09 mirror all of HTML in Python.

19:12 And for those of us who are happy writing HTML or writing React, that sounds like hell.

19:16 It's going to be slow because you have to do some weird rendering, but it's also just

19:19 going to be a picky because I don't want to have to define every A and Href and everything

19:23 else in Python code.

19:25 It's just, and there are going to be, it requires for start, it requires you to know two things,

19:29 Python and HTML, whereas HTML, you only need to know one.

19:35 This portion of Talk Python to Me is brought to you by Bright Data.

19:39 Bright Data helps you turn websites into structured data.

19:43 There's an unimaginable amount of data available on the internet.

19:47 And we're lucky to live in a time where we have so many APIs to access structured data.

19:53 But the truth is that most of the data out there is not served up over a clean API.

19:59 Just sitting there on a web page as HTML.

20:02 Maybe it's even further obscured behind some front end JavaScript framework like Vue or

20:06 react.

20:07 What if you need access to that data?

20:10 Web scraping to the rescue, right?

20:12 Yes, but just like you wouldn't set up your own production infrastructure in your home

20:17 office, running a web scraping job on a single computer at a fixed location can lead to your

20:22 program being unreliable with data pinned to that IP location and much of the time blocked

20:28 for rate limits and other such causes.

20:31 If you need to do professional web scraping, bright data is the place to start.

20:36 They have award winning proxy networks and powerful web scrapers.

20:40 What's more is they have ready to use data sets for download.

20:43 So you might not even need to scrape data at all.

20:46 And if you can't find the data set in their marketplace, they'll even build a custom data

20:51 set for you.

20:53 From listening to the show, you know that I'm a privacy conscious person.

20:57 And that's why I'm happy to see that they are both CCPA and GDPR compliant.

21:02 Bright Data has both low code solutions as well as Python programming models with async

21:07 IO and playwright.

21:09 So if you have serious data needs, and those websites don't offer API's, then you need

21:14 bright data, check them out today at talkpython.fm/brightdata.

21:19 And please use that URL that way they know you heard about them from us.

21:24 That's talkpython.fm/bright data.

21:27 The link is in your podcast player show notes.

21:29 Thank you to bright data for supporting the show.

21:33 I always find these things that try to dodge like dodge the fact that HTML exists.

21:37 I find them I just they don't resonate with me.

21:40 I'm not entirely sure why it's like we have really nice things like CSS and we have really

21:46 all there's just so much tooling and frameworks, you know, you mentioned bootstrap already,

21:53 right, that just plug into there.

21:54 And if it's like, well, we're just going to write, recreate it in Python.

21:58 Well, it has all the oddities of HTML if it's going to be really high parity, and then you

22:03 just have a less well known way to do the same weird thing.

22:06 You know, I don't know, just it doesn't resonate super with me.

22:08 I agree.

22:09 And I found the same thing at times with ORMs that you end up the worst case of an ORM is

22:14 you work out what you need to do in SQL, then you try and translate back from SQL to ORM.

22:19 And it would be much nicer just to write my SQL.

22:21 I mean, not always the case, ORMs can be powerful, but I think that they, they both can fall

22:25 into the same same trap if you're not careful.

22:28 And then I was gonna 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 for understandable reasons could suffer from

22:35 this that you basically have a very small set of things you have a like a table page

22:38 and a details page and a form page.

22:40 And that's kind of it, right?

22:41 So there's this difficult trade off in where in that continuum do we try to choose what

22:46 size of component to implement, right?

22:48 So for example, here we have, we have a heading, which is almost one for one matches what you

22:53 would do in HTML.

22:54 We have the text that goes within it and we have the level, which, you know, it's slightly

22:58 different syntax, but it's basically one for one matching an HTML tag.

23:02 But then we have a table, which it doesn't look very much like an HTML table at all.

23:07 We're not having to explicitly define the table body versus the table head.

23:12 We're not having to put in each column.

23:14 We're not having to worry.

23:15 Yeah, there's lots of stuff here that is much less like it.

23:17 And that's where it's in these very common components where there is consistent things

23:23 that lots of people want to do, or lots of places in your app where you might want to

23:26 do them, where I think a framework like fast UI gets gets super powerful because we can

23:31 get you a table here with with users defined and with a few columns with some customization

23:37 on what happens when you, how we render each column much more quickly than we could go

23:41 write out all the HTML for that.

23:43 And it's much more concise to read it.

23:45 Like it's consistent enough that something like Copilot will help you write it out where

23:51 you do have a bit of customization to do.

23:53 I think this, this is where it can be super powerful.

23:55 Yeah, it's, it is pretty interesting.

23:56 And I like the hierarchy for people listening, just check out github.com/pydanics/fast UI

24:02 and the example right there on the page.

24:04 But what you do is you create a, in this case, a FastAPI, API endpoint, and then you return

24:10 a hierarchy of elements out of fast UI.

24:13 So we have a page, the page has components, the components are a list of a header in a

24:17 table, the table has data, which maps over to a list of pydantic models, which then help

24:24 say what goes in the field and for the column headings and things like that.

24:29 It's pretty interesting.

24:30 I think it's neat.

24:31 And obviously we can add other components like pagination that works.

24:34 I think just, just to come back to the top, to how we do these views, the very simple

24:39 and it's most simple what fast UI's react app does is it basically takes whatever the

24:44 URL is you go to.

24:46 So in this case, you might go to slash to the base URL and it pre-pens slash API and

24:52 makes a request to that endpoint to basically say, what should I render?

24:56 And it gets back.

24:57 And so this here, where we're basically returning a list of pydantic models, all the fast UI

25:03 model is really doing is taking that list of pydantic models and calling model dump

25:07 JSON on it to get the JSON that we returned to the front end.

25:11 As I say, the front end then knows how to render each of those.

25:16 Each dictionary in the list is what it is at its core.

25:18 At its core, it's a, it's a list of objects to use JavaScript parlance.

25:22 It just knows how to render each of them and renders each of them in turn.

25:25 And then obviously they can then have nested other models, all of which it knows how to

25:29 render.

25:30 Yeah.

25:31 It reminds me of a couple of things.

25:32 I have an example of this, no, somewhere along here.

25:34 I pulled it up.

25:35 It reminds me of kind of what react looks like.

25:39 If people have done react, you know, you write a function that returns kind of an HTML thing,

25:45 but then it has JavaScript arrow functions, right?

25:48 It's a, but it has the same nested feel, right?

25:52 Did react inspire you to create it this way or not really?

25:55 Yeah, it did.

25:56 I've done quite a lot of react and I like it a lot.

25:58 I know there were as a, as a popular piece of technology, there were lots of people who

26:02 like to like to break it, but I do think react.

26:06 So like being a powerful step forward and the greatest form of flattery is, is copying.

26:11 And there are enough other, like sure there are other more powerful, arguably more powerful,

26:16 arguably more performant new front end libraries, but everything is, is component based now.

26:21 Like, you know, react has changed, changed the, was the sea change in how we did front

26:25 end with that component architecture and JSX similarly is, is superpower.

26:29 So one of the things that I think we're going to get to, I don't want to dive into it yet,

26:32 but like in react, you would say like, we're going to return a photo contacts, a context

26:37 or a switch or something that is not typically known in HTML.

26:41 And these are higher order building blocks in the UI space.

26:45 Right?

26:46 So when people think about what they're creating here in Python, it's not just the fundamental

26:51 DOM objects and elements, is it?

26:54 Right.

26:55 So that, that, that was actually, yeah.

26:56 So page here is a bit of ambiguity about how we're going to define a page.

26:59 Like default implementation does, does something reasonably sensible.

27:02 It like, you know, pads it, et cetera.

27:05 But like heading isn't, there isn't much to do really.

27:08 You're going to return a heading, but when you come to a table, there's a lot of debate

27:11 about how you're going to do that.

27:12 And then when you move on to like even higher order components, like a modal, then that's

27:17 the, the, how exactly that's implemented is, you know, in some sense it's to completely

27:21 the choice of how you've implemented it in the front end.

27:23 You could, you could do lots of different things, but yeah, the whole point is that

27:26 it doesn't and shouldn't be like each HTML tag is written out.

27:31 Cause as I say, I think that would be a like obvious failure mode for this.

27:34 Yeah.

27:35 The other thing this reminds me of, by the way, just for people out there listening is

27:40 it looks a lot like a flutter.

27:42 If people have done any flutter, you've got these widget hierarchies, you build them,

27:47 you maybe set some properties, you add in a bunch of, a bunch of elements, you know,

27:53 set some children to an array of other sub elements.

27:56 And this is done of course in Dart, but it's, you know, this is kind of a Python version

28:01 that's similar as well, these higher order widgets.

28:03 Yeah, absolutely.

28:04 Similar thing.

28:05 And actually the other place where I've built this before is that internally Pydantic core,

28:10 the Rust bit of Pydantic is effectively not entirely different to this, right?

28:14 You define these nested structures of validators.

28:18 Everything at its core is a like combined validator, which is in Rust terms, an enormous

28:22 enum of all the different types of validator, some of which have nested within them, more

28:26 and more validators.

28:27 And that's how you build up nested structures of Pydantic models, which in turn is what

28:32 these are.

28:33 We're getting a bit of it.

28:34 Yeah.

28:35 The validators and the UI, they kind of like have a similar structure.

28:37 A bit of a sidebar, just a bit of piece of code in here.

28:40 You've got table, which is a class, square bracket, user, which is another class, square

28:46 bracket.

28:47 I imagine that you and your team are deeper into the Python type system than the vast

28:53 majority of others out there with all the work with Pydantic and the interoperability

28:57 with Rust.

28:59 What is that?

29:00 Tell people about this.

29:01 Yes, a table is a generic.

29:03 So you can imagine if you were doing list of ints, you would do list square bracket

29:07 int.

29:08 And that's basically the point is that list is a generic around its elements, same as

29:13 a dict is generic around its keys and its values.

29:16 While table here is generic around the Pydantic model that you're using for each row.

29:23 And particularly what that means is that what it means practically is that table has access

29:27 to the class when it's deciding what the default columns are.

29:32 So if you don't define the columns list as we have here to say what columns to display,

29:36 it'll show all of the fields in the Pydantic model.

29:39 And the point is we get access to that to the user before we've, even if the data was

29:44 empty before the validation has happened.

29:47 Is it necessary?

29:48 Is it slightly like, yeah, fancy use of Pydantic types, Python types, maybe it is.

29:54 But yeah, if you know, forgive the Pydantic team or me in particular for occasionally

29:58 doing fancy things with Python types.

30:00 That is definitely occupational hazard of what we do.

30:02 Yeah.

30:03 I didn't mean it as a negative.

30:04 I just thought it was interesting.

30:05 No, I agree.

30:06 And actually I had it somewhere else on forms and I removed it and realized it was, it was,

30:10 it was unnecessary.

30:11 So you can definitely do too much.

30:13 Such a thing as too much Python typing.

30:15 Yeah.

30:16 Yeah, for sure.

30:17 It is pretty interesting.

30:18 So let's maybe talk about some of the examples.

30:21 Actually before we do, just give us a sense of where does this fit in the UI space for

30:27 Python?

30:28 On one end we've got Flask, Django, FastAPI, returning HTML, et cetera, where it's all

30:35 on you.

30:36 You're doing all the five languages of web apps, SQL or some query language, Python,

30:43 JavaScript, CSS, some other tools, right?

30:46 Like you're doing all that and you're doing my hand.

30:48 On the other end, we've got tools that are pretty cool.

30:50 Like we've got Anvil that lets you just write Python and do a draggy droppy sort of thing,

30:56 which is, is really neat, but it fits into a kind of a box for those types of apps.

31:00 I just discovered DropBase.

31:02 Have you heard of DropBase?

31:03 Not seen DropBase.

31:04 Yeah, but I've seen a lot of these like, get me a UI more quickly.

31:09 A lot of them are like kind of low code.

31:11 Anvil, maybe I wouldn't really quite put it there, but they're pretty like low code, but

31:14 then there's places where Python goes to make it dynamic.

31:18 Right.

31:19 So we're in that spectrum.

31:20 Would you put fast UI as it is today?

31:23 Interestingly.

31:24 One of the reasons I wanted to come and talk to you was I heard you were talking the other

31:27 day on your other podcast, and I heard you talking about fast UI and kind of, I'd say

31:32 categorizing it into that group.

31:34 And what I wanted to kind of, one of the things I wanted to come and say was, yes, we can

31:38 do that, but the use case we have within Pydantic is actually to go and build a pretty complex,

31:44 fully fledged application with front end developers building components, but just get rid of that

31:48 churn.

31:49 Right.

31:50 So it's more like Gmail, less like here's a table that I can click on and see some related

31:56 table.

31:57 Right, exactly.

31:58 And then what I should probably put in the demo and probably where Pydantic is people

32:00 most associated and where this is going to be most useful is within forms.

32:05 So I don't know if you want to go to the demo and I can talk people through, but like within

32:10 fast UI is dedicated to forms.

32:12 We can do things like nested Pydantic models all become components within a form.

32:17 Then obviously we can do client side validation with a whole bunch of stuff, but we can also

32:21 do server side validation, but then we get all the fancy stuff.

32:24 Like if the data is invalid and you get a validation error on the server side, we'll

32:30 then basically re-render the form with the errors in place, all that stuff that like

32:35 anyone building a web application has to go and implement some version of it.

32:38 At the moment there are some React libraries that will build you a form from JSON schema,

32:44 but they don't perfectly fit in with what Pydantic does or with FastAPI.

32:49 And so I have built some variant of that about five times.

32:53 I still think the state of the art until now is Django, but like lots of us don't want

32:57 to build our web applications completely with Django because it's pretty all or nothing

33:01 despite the wonder that is Django.

33:03 And so that's the kind of space where for me, this like becomes a really stands out

33:09 because what would have been to do it properly, it's days of work to get form validation,

33:14 to get form submission to work, get client side validation, server side validation, get

33:18 the redirect after your form.

33:19 None of that stuff is entirely trivial, even for those of us who've done it before.

33:23 Whereas the theory is with fast UI and in, although fast UI does not require FastAPI,

33:30 the form stuff is quite tightly integrated with FastAPI and you can get a really good

33:35 experience of building stuff like forms.

33:38 I think that where the alternative really today is to use, no disrespect to any of the

33:44 fast libraries or any of the other things, but I think the only real alternative right

33:48 now is implementing yourself or use Django.

33:50 - Yeah, but I do also want to, but maybe before we get to that, let's try to take a little

33:54 survey of what are these widgets, these building blocks that you can use.

33:58 Yeah, is that right?

33:59 - Yeah, absolutely.

34:00 - I think I can find them here.

34:01 Yes.

34:02 Yeah.

34:03 So you have a UI demo, which I'll link to at onrender.com, the prefix, but you talk

34:08 about some of the things that you can just create in that Python hierarchy that you return

34:14 that builds up your UI there.

34:17 So maybe you talk us through some of the things that are here.

34:19 - Yes.

34:20 We have the kind of generic markdown component, which will go up and renders a markdown.

34:24 This table itself is implemented using the markdown component.

34:27 Just one side note, the markdown and the code, because they have quite a lot of JavaScript

34:32 associated with them, they're actually lazily loaded to make the prebuilt fast UI app faster

34:38 to load.

34:39 Then we have text, probably the simplest one of all, just render some text.

34:42 Paragraph, again, very simple.

34:44 Page titles, a slightly funny one.

34:46 It doesn't actually display anything on the page, but it changes the browser title.

34:50 So what you see in the tab at the top of the page.

34:52 - It's not always easy to do.

34:53 Like how do you inject it into the head when you're in the body?

34:57 It takes a little bit of integration there, yeah.

34:59 - Right, exactly.

35:00 So again, very simple, like one to six HTML heading.

35:03 Code, a bit more sophisticated.

35:05 And if you click on code, maybe those who can see it will be able to click through.

35:09 Oh, code is, yeah.

35:10 So code is there.

35:11 We get a highlighted bit of source code displayed.

35:16 - It's color coded with class types having a color and keywords having a color.

35:20 That's nice.

35:21 - Like you would see in GitHub or something like that.

35:23 So again, just work out of the box.

35:25 Then we have some components like a link list and link, which are used in other components

35:30 mostly.

35:31 So if you, the nav bar you see at the top of the page there, that uses a link list and

35:34 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 loads a modal and then the button, which loads

35:41 a dynamic modal.

35:42 So when the modal loads, it will make a request to get the content you want to see within

35:46 that modal.

35:47 So that could be a form or it could be customized depending on the form in the page.

35:52 Then we have loading content from the server, which is the same thing we were doing in the

35:55 modal, but on the page.

35:56 Then we have this SSE component.

35:58 So again, very simple to use within Fast UI, but like quite a lot of work to use server

36:03 side events to basically dynamically update a React component if you weren't using that.

36:08 - So your server load SSE widget, that provides, like you said, server sent events, which I

36:15 don't know how many people are familiar with SSE.

36:17 I'm sure they're familiar with WebSockets and they're familiar with just like a JavaScript

36:21 event.

36:22 So it's like an immediate sort of lightweight, one directional, but normally the opposite

36:26 in reverse, I guess, from the server to the client, sort of pushing out stuff.

36:29 So that's a really powerful thing.

36:31 And if it's that easy to just hook a function call when something happens, that's pretty

36:35 cool.

36:36 - One of the things I want to try with SSE that I think will work really nicely is LLM

36:40 responses where you get like one token at a time because you don't want to wait for

36:42 the whole thing.

36:43 - Yeah, exactly.

36:44 - The event would be perfect for basically printing out the response from an LLM.

36:48 And again, it would be like two lines of code to add that to an app with Fast UI.

36:52 It would not be two lines of code to go and implement that yourself, whether you're using

36:56 pure JavaScript or React or whatever framework.

36:59 And we have iFrame, which again, kind of map, we're back to kind of mapping one-to-one to

37:03 a component.

37:04 One of the nice things to say about both iFrame and images, they were contributed by other

37:08 people.

37:09 So I don't think I'd even created an issue asking for them, but people have come along

37:12 and added them.

37:13 It's been one of the nice things to see.

37:14 I think we had 18 or so people contribute to the first release, first release after

37:18 my initial release, or sorry, the second release of Fast UI.

37:22 So yeah, good engagement from lots of people.

37:24 Image.

37:25 - Yeah, so you've got a bunch of UI stuff here.

37:27 And it just, as I look at this and I see what you're building, it just makes me think of

37:32 like, wow, there's an opportunity for stuff like what you get out, not necessarily the

37:36 same as, but like what you get out of say, Tailwind UI, where the things you might work

37:41 with are on-off switches, you know, like toggles, like you might see in your phone or other

37:46 sort of elements that have like a lot of design imbued in them that people can just grab and

37:52 use, almost like a Django philosophy for the front end, in a sense there.

37:57 Is that something that you are dreaming of or?

38:00 - Someone was complaining somewhere that we didn't have a grid component yet.

38:03 And I think we'll do one, but like those bits get quite opinionated, but yeah, like calendar,

38:07 completely obvious choice, right?

38:10 Complete faff to go and implement that yourself in HTML, commonly used, trivial to define

38:14 because the definition, there aren't that many different things to define.

38:17 You choose your month.

38:18 You know, most of us are on the Gregorian calendar, right?

38:21 We're not going to have to change too much what calendar we're going to render.

38:25 So yeah, that's a perfect example of the kind of thing.

38:28 Tiles like this, again, totally possible to go and implement them.

38:31 And again, obviously you can use, we can provide some nice default, but also if you're a bigger

38:36 company and you want to go and customize it, you can totally do that.

38:40 And you can have a front end developer go through and implement the classes that basically

38:43 customize the look.

38:45 I wanted to come back just to show you some of the other components.

38:49 So we were on, yeah.

38:51 This one here.

38:52 I don't know if we have anything more below that, but I would love to show you the tables

38:55 because the tables and the forms of really where it comes into cities is probably the

38:59 best example.

39:00 Okay.

39:01 Yeah.

39:02 Awesome.

39:03 This is a list of cities just for some public data set with country and population.

39:06 But at the top you see we have a filter to choose by country.

39:10 And if we click here, if you start searching like UN or something, you'll see we're doing

39:14 a server side.

39:15 We're loading from the server, the list of cities.

39:17 So again, this component to go and implement, if you were going to do that from scratch,

39:21 you've got to have you some like clever, this is a list of countries.

39:25 So if you do like, oh, country, sorry, I'm typing in cities.

39:27 Good.

39:28 Like UN, you'll get United Kingdom and United States.

39:30 Perfect.

39:31 There you go.

39:32 And then we do United States or whatever.

39:34 Yeah.

39:35 And then we'll get a bunch of cities in the United States.

39:38 Building this and wiring it all up and using one of the, we use react select here, but

39:42 you can use select two or one of those components.

39:45 It's not trivial.

39:46 You need to also set up the backend.

39:47 You need to set up this.

39:48 There's like a few hundred lines of react dedicated just to setting up those, those

39:53 selects correctly.

39:55 And as you'll see in a minute on a form, you can add this to a, to form with us.

39:59 You are pretty trivially.

40:00 Secondly, if you go to the bottom of the page on cities, you will see pagination again,

40:05 not a trivial thing to go and set up.

40:07 If you've got, if you're just starting from scratch and you want to show like build an

40:10 internal endpoint, for example, to show all of your users doing all that pagination and

40:14 like wiring all that up is not trivial, but we effectively do the work for you to have

40:18 that component and do the maths of which page we're on and stuff like that.

40:22 I want to reiterate, this is the fast UI is not just designed as a kind of Django admin

40:27 interface alternative.

40:29 We within Pananzi are going to go and use it for UI that we're going to show to end

40:33 users.

40:34 But obviously it also comes into its own when people want to just get something up quickly.

40:40 This portion of Talk Python To Me is brought to you by Sentry, you know, Sentry for the

40:44 air monitoring service, the one that we use right here at talk Python.

40:47 But this time I want to tell you about a new and free workshop.

40:51 He mean the Kraken managing a Python monorepo with Sentry.

40:55 Join Salma Alam Nayyar, senior developer advocate at Sentry and David Winterbottom, head of

41:01 engineering at Kraken technologies for an inside look into how he and his team develop,

41:06 deploy and maintain a rapidly evolving Python monorepo with over 4 million lines of code

41:13 that powers the Kraken utility platform.

41:16 In this workshop, David will share how his department of 500 developers who deploy around

41:20 200 times a day, use Sentry to reduce noise, prioritize issues and maintain code quality

41:26 without relying on a dedicated Q&A team.

41:29 You'll learn how to find and fix root causes of crashes, ways to prioritize the most urgent

41:34 crashes and errors, and tips to streamline your workflow.

41:38 Join them for free on Tuesday, February 27 2024 at 2am civic time.

41:43 Just visit talkpython.fm/sentry-monorepo.

41:47 That link is in your podcast player show notes.

41:50 2am might be a little early here in the US, but go ahead and sign up anyway if you're

41:54 a US listener, because I'm sure they'll email you about a follow up recording as well.

42:00 Thank you to Sentry for supporting this episode.

42:05 If we have a design language or something like that, or even using a framework, I mean,

42:09 you mentioned bootstrap, but tailwind or Bulma is that one of the new ones?

42:13 Like if we're working with one of those, and we wanted to use this, like how easy is it

42:19 to sort of bring in those elements there?

42:21 So if I show you here on boot, so I'll show you how we customize it with bootstrap, which

42:26 is probably the best definition of it.

42:28 So you'll see here, this is in the, this is the, where am I looking?

42:32 This is the prebuilt version.

42:33 So this, this is obviously the prebuilt version of fast UI you can get, but it's actually

42:38 just, it's a very simple app in terms of react.

42:41 This app has one, well, two components.

42:43 It has a div which contains the fast UI component, and then we customize it in a bunch of ways.

42:48 We have a like component that we render for not found.

42:50 We have a component we render for spinner and for transitioning.

42:53 But then these are the two that really matter, where we can customize the classes and we

42:57 can customize how we render certain components.

43:00 So if we come in here to have this function from bootstrap, which is how we customize

43:04 the classes, you'll see that at its core, it's just this big old switch.

43:08 So this is all a TypeScript, like type safe because types are very powerful in TypeScript,

43:13 but like all of the props will have this type key.

43:16 As I showed you earlier, when we were looking at the Python code, That's like, and all the different things.

43:21 Yeah.

43:22 Based on the switch, we just go through and this is all just like defining the classes

43:25 we want for all of the different components.

43:27 Some of them depending on the exact state of the component.

43:30 So all of these form inputs, we customize them depending on which type they are and

43:34 on which mode we're in, et cetera, et cetera.

43:36 But it's all very mechanical, just like laying out the classes we need for each individual

43:41 case.

43:42 And then we have the other way of customizing it, which is to use custom components.

43:46 We basically for three in particular components, navbar, modal and pagination, we define our

43:52 own custom React components.

43:54 So here's the one for navbar where we use a bunch of bootstrap types to render a bootstrap

43:59 navbar.

44:00 So you could basically create a React component that has all the settings necessary to create

44:06 a navbar in Tailwind or whatever.

44:08 Right.

44:09 And then just plug that stuff in.

44:10 So if you wanted to use Tailwind, what's this, like 20, it's like a hundred lines of code

44:14 to define all of the classes.

44:16 And it's pretty mechanical code, right?

44:18 So it would be, it wouldn't be hard at all to go and use Tailwind, Tailwind CSS.

44:23 And then you might want to define a few of your components specifically.

44:26 But actually modal, I think is the only one that really requires it to be custom implemented

44:30 because the default just shows you an alert because there's nothing.

44:35 The page says, it's like, ah, no, the page doesn't say this isn't going to work.

44:39 Yeah.

44:40 So yeah, I think this is one of the bits I'm most proud of here is that like how much you

44:43 could customize it and how simply you could start to customize it.

44:46 Right.

44:47 Those are really like kind of pluggable or extensible.

44:49 So you don't have to get in and know too much about it.

44:53 You just plug in the class name generator and the renderer for a specific one.

44:58 And so, yeah.

44:59 And all of the types, it's all typescripted.

45:01 So the types should do a lot of help telling you what you can implement.

45:05 Last thing I'll show you is, yeah, so here in the default build, as I said, we, our custom

45:10 render function is not just a bootstrap one.

45:13 We do one special thing, which is where we have this idea of a custom component, which

45:18 basically all it has is a subtype, which basically you should use to render it however you like.

45:24 So in our case, we take custom and if the subtype is cow say, we render that as a particular

45:31 block, like use this component here.

45:34 And we print out the cow says whatever it was that the input was from the server.

45:37 And otherwise we just go back to using the bootstrap render.

45:39 And so if you look at that component here, yeah, we've got this like slightly silly example

45:45 of a custom component of cow say saying something.

45:47 Oh, that's fun.

45:48 But yeah, it shouldn't be too difficult to customize.

45:51 And then even if you're customizing to go back to using bootstrap for the full back

45:54 case of everything else.

45:55 Okay.

45:56 So you could almost just for one section that has to be really specialized to some custom,

46:01 but otherwise just lean on a framework.

46:02 Yeah.

46:03 Okay.

46:04 Yeah.

46:05 This looks like something that one person could take one for the team, create a tailwind

46:09 or a whatever generator, class name generator, and then put that as either a contribution

46:14 or put it up on GitHub and then you just, you're kind of good to go.

46:18 Yeah.

46:19 I think we might, we might actually do it.

46:20 We're, we're using tailwind and radix within Pythontics.

46:23 So I suspect our front end guys will at some point get annoyed with my use of bootstrap

46:27 and go off and go and change it.

46:29 One of the reasons I use bootstrap is that because bootstrap is completely customized

46:32 via SCSS and the SCSS compilers for Python, we have the, at least the possibility in future

46:39 to allow you to customize the complete look and feel of your app without ever having to

46:43 touch NPM because you just go change basically the color definitions as we do here.

46:48 So, so the, the default version of maybe I can even change it here and as it's running,

46:53 it'll change.

46:54 But if I hear you say I've set the primary color to be black and so you'll see the buttons

46:58 here are all rendered as black.

47:00 If I were to change it, I haven't tried this for a bit, so I hope it works.

47:04 Comment it out primary.

47:05 You'll see that all of the primary, which is the bootstrap primary button.

47:11 And if I changed it, I got rid of the default font, you would see we went back to whatever

47:16 the other font was.

47:17 So there's a world in future where we allow you to customize the look and feel even within

47:21 bootstrap from Python code.

47:22 Yeah.

47:23 Tell people maybe who don't know what SCSS is.

47:25 They probably know what CSS is.

47:27 It's generally referred to as SASS, which is S A S S, which was, is, is basically a more

47:34 powerful version of, of CSS where you can.

47:36 SAAS and LESS.

47:37 Those were the two.

47:38 Yeah.

47:39 And then we kind of settled on SASS, but then we had SCSS, which is SASS with more CSS syntax.

47:46 It's a way to like do slightly more powerful things in, in CSS and minify it and have stuff

47:52 like variables for they were available in CSS and defaults.

47:56 And even you can do weird stuff like map functions and they use very heavily in bootstrap.

48:01 But the nice bit is because the compiler is written in C, there's lib SAS in Python where

48:06 you can get kind of a front end customization without needing the whole of node and the,

48:13 the whole dog and pony show front end of it.

48:15 Yeah.

48:16 Excellent.

48:17 It's got a lot of legs.

48:18 So when I saw this and I saw, okay, this is a, for, for web apps and it's kind of got

48:22 this, this Python code running that defines the backend and it's got the UI and it's all

48:27 a little self-contained.

48:29 One of the thoughts I had was, wouldn't it be neat if there was a, got a little bundler

48:34 type of thing that made this into an electron app.

48:36 Would this be possible?

48:37 Can we get something that you could send out?

48:40 Or is this really just going to be intended to be kind of a, a friend of Django type of

48:45 thing?

48:46 I have not used electron for a very long time, so I don't pretend to be an expert.

48:50 What I will say is that unlike some of the other UI libraries, we're not trying to do

48:55 clever things with web sockets and do all of the, all of the rendering requiring duplex

49:00 communication between the client and the server.

49:02 It's pretty simple.

49:03 It's like make a request and the JSON contains some information about how to render it.

49:08 And then the front end goes off and renders it.

49:09 So it's the result, what you get when you finish is very, in terms of a networking point

49:14 of view, very, very simple, very conventional.

49:17 It's like make an HTTP request to get back JSON, JavaScript knows how to render it.

49:21 And so I don't see why it shouldn't, shouldn't work in, in electron.

49:25 There's even the world in which we don't need the whole of electron and we could, someone

49:29 could go and build fast UI components for whatever native library, and we could get

49:34 like native apps running that are based on fast drive.

49:37 Not saying that's necessarily a good idea, but like those possibilities exist.

49:41 It is, it does exist.

49:42 Okay.

49:43 Yeah.

49:45 Very interesting.

49:46 Another thing that is convention, I suppose, I'll see if I can pull it out here is the

49:49 UI.

49:50 A lot of times you'll have either just slash or have slash users, but then you'll have

49:55 an API that backs it.

49:56 And there's this convention that if it's in the URL, if you have slash API slash, in this

50:01 example we were talking about before, it's like slash table slash cities.

50:04 If you say API slash table slash, that's the data endpoint.

50:07 And then if you drop the API, that's the front end that then turns around and calls the backend

50:12 with the API inserted.

50:13 Right.

50:14 You want to talk about that convention a little bit so people kind of see where that's going.

50:18 So that's how, how I've set it up in the default app.

50:21 It doesn't, you don't have to do it like that.

50:22 And I think we're using a separate subdomain to avoid like path-based routing and all that

50:27 fun.

50:28 But yeah, the, the, the principle that the default simplest way of basically doing a

50:32 calc excuse me, a calculation to go from, I've got a URL, how do I get the data for

50:36 it is as I said earlier, basically prepend slash API.

50:40 So maybe a more general way to think about it is for every page, there is an endpoint

50:45 that is a FastAPI endpoint or a pair of them.

50:47 Maybe even the one returns the HTML front end stuff that makes it run that talks around

50:53 and goes back to itself.

50:54 Right.

50:55 Yeah.

50:56 So what we have in the default app here, what I would generally recommend is where are we?

51:00 We have a bunch of routers that connect and do all of the API stuff.

51:05 And I've just been implementing all which I can show you in a minute, but that's not

51:08 available as a PR for it, but it's not available in the demo you're looking at.

51:11 But then we have this like basically catch all endpoint, which if nothing else has been

51:15 hit, will render the standard HTML.

51:18 And one of the nice things is that the Python library gives you this prebuilt HTML, which

51:23 will basically render you the HTML that you'll get if you went here and I view page source,

51:30 you see returning.

51:31 Yeah.

51:32 Well, yeah.

51:33 And this particular, if I went to 8,000, then it wouldn't be messed up by beat.

51:37 You just get this very simple HTML, which in turn renders the app.

51:39 So yeah, there's effectively, you're right.

51:41 There's two, there's two, there's a like matching endpoints for, for every view you might want

51:45 to have one to get to return the Json, the one to render the HTML.

51:49 But you don't write, you don't write them both, right?

51:51 You write the API one and then fast UI magically turns out into UI.

51:56 Right.

51:57 And whatever, and this would all of most of this, with the exception of the form submission

52:01 would all just work out the box with, with any Python web framework.

52:04 You just need to produce your financing model, dump it to Jason and return that in a response.

52:10 But one of the really nice things about the, this being the like actual data existing in

52:16 Json is that writing a test, there's quite a lot here, but you'll see most of it is,

52:20 is Markdown.

52:21 So writing a test that our views contain what we expect them to is massively easier when

52:26 we're testing against Json, which we can convert to Python objects and tests.

52:30 Then it would be if we've got an HTML page and we're running a bunch of regexes for,

52:33 does this page contain the user's name?

52:35 Does it contain the word log out?

52:37 Blah, blah, blah.

52:38 Yeah.

52:39 So you can just say, write type of things or those types of tests.

52:42 Sure.

52:43 Oh yeah.

52:44 Even worse, you end up with that play wright and like play wright that's image of it and

52:47 see if the image looks like the image used to look and yeah.

52:50 Things I don't want to have to build.

52:51 I mean, they have to happen occasionally, but like we're, and ironically we'll probably

52:55 end up with them in fast UI to like even more certainty that our components work correctly,

52:59 but hopefully that thereby avoid everyone else having to, having to go and build them.

53:03 Is there any concern that maybe there's unintended APIs in the sense that like all of the stuff

53:09 I'm sure this is probably true for pretty much any react site, but like a lot of the

53:14 page is available also as an API, even if you don't intend it to be an API, like what's

53:19 yeah.

53:20 That's a limitation of any, I mean, in some ways the data will be slightly less nice to

53:24 yeah.

53:25 You're right.

53:26 If you're a company that give people foreign exchange rates and you want them to always

53:29 come to your site, you obviously can't render that with, with react because there's going

53:33 to be a JSON endpoint where someone can just go scrape your exchange rates or whatever

53:36 else.

53:37 Right.

53:38 And if you have a function based off and say you have to log in to do it, right.

53:42 It's not just that it's public.

53:44 It just, there's always a JSON version, but honestly there's so many interesting ways

53:48 to pull data out of HTML.

53:50 Like if someone will do it anyway.

53:53 I also think that like in theory, if your options are build pure react or do this, and

54:00 this has the, the, like, as I say, there's the realistic chance someone's going to come

54:03 along and implement a fast UI front end that, that renders HTML.

54:07 And then, and then you don't have to expose your expose those JSON endpoints at all.

54:12 And you could, you could return HTML from your server.

54:14 We just haven't got around to building it yet.

54:16 Yeah.

54:17 I guess you could maybe do some kind of server side rendering potentially as well.

54:20 Exactly.

54:21 That's what I mean.

54:22 Whether it's server side rendering or whether it's JavaScript server side rendering or whether

54:25 it's edge rendering, I've tried to build a sort of edge rendering thing in Cloudflare

54:29 years ago using Rust and for a bunch of reasons it didn't quite work, but there's real possibility

54:34 of doing like, yeah, any number of different things in that direction.

54:36 Oh, that's interesting.

54:37 I know the CDNs have pretty dynamic stuff right at the edge where you can sort of put

54:42 your last bit of code.

54:43 I haven't done anything with that.

54:44 That's kind of what Remix is doing and Next.js to a lesser extent.

54:48 So, but again, in theory, the, I mean, maybe I'm overblowing it and fast UI will remain

54:53 what it is now, but like in theory, we just, we've set up this, this language of different

54:58 components that, that hopefully is whilst by no means universal, complete enough that

55:03 you can build lots of common user interfaces with it.

55:06 And then if it really gains adoption, then people can go build new backends and new frontends

55:10 and they all in theory should be able to mix and match with each other.

55:14 We'll see if that happens.

55:15 Yeah.

55:16 And widgets too, right?

55:17 Kind of like see a Tailwind UI create a paid thing for higher order widgets, potentially

55:22 just being React already makes that, that probably exists.

55:25 I just don't know.

55:26 And there's, there's been a number of issues of people wanting to render existing, basically

55:31 build extensions to fast UI to render their widgets.

55:33 I think we will probably support the repo HTML that things like pandas data frames already

55:38 returned so that you could, for example, return a data frame and it might not be pretty, but

55:42 you'll get something coming up as HTML and, you know, start ugly and then move on to doing

55:47 those things in an even more powerful way.

55:49 Sure.

55:50 Yeah.

55:51 I didn't even think of the data science side, but there's probably a lot of cool dashboard

55:53 widgets connected to pandas and pullers that are potential out there.

55:57 Yeah.

55:58 And charts and visualizing data is something I don't think is interested in.

56:01 There's no reason why a lot of them couldn't be implemented as fast UI components and then

56:05 displayed.

56:06 Okay.

56:07 We are running pretty short on time.

56:09 I feel like we should probably bring a little more Pydantic to the side and just talk real

56:14 quickly about forms, right?

56:15 What do you think?

56:16 Yeah, absolutely.

56:17 So if you, probably easiest if you share, let me see, share my screen.

56:20 I'll do it from here.

56:21 Cause I can also, it's like the form is pretty boring.

56:24 You can show me behind the scenes.

56:25 Yeah, yeah, yeah.

56:26 It's probably most interesting if we, if we look at the, how the form is implemented in

56:30 the code first, and then we look at what that, what that means for the UI.

56:33 So this is the login form that Michael, you were just showing here that I can show, which

56:37 is a login form with an email address, password, some validation, basically like that.

56:42 Yeah.

56:43 Powered entirely by, again, a completely vanilla Pydantic model.

56:46 And the way that we return that is we return three things, a heading, which is like telling

56:52 the person what we're looking at here in the demo.

56:54 And then this third thing is that it's interesting bit where again, actually the model form is

56:58 again, generic around the Pydantic model.

57:01 And then it takes one other argument, which is the submit URL.

57:03 And that's enough information.

57:04 Right.

57:05 So what you're returning as part of that hierarchy in Python is a model form and you give it

57:11 a Pydantic model.

57:12 And so it looks at the Pydantic class and says, we're going to create like an email

57:17 address and a password field and so on.

57:19 Right?

57:20 Exactly that.

57:21 Awesome.

57:22 Okay.

57:23 And then when you submit that form, it's submitted as form data.

57:26 So as not as JSON data, but as a vanilla HTML form.

57:30 A standard form post type of thing.

57:33 Post form.

57:34 And then we have this, it's this syntax is definitely slightly funky here, but it's how

57:38 we do it in FastAPI.

57:40 We have form, which is annotated as a login form, but it's also got fast UI form, which

57:45 in turn, which also takes login form, all of which looks a bit ugly, but what we're

57:49 really doing in the background is converting form data into the Pydantic model, including

57:56 flattening and deflattening the model in the case where we have nested models, which I'll

57:59 show you in a minute.

58:00 But the result of this is once we, in our, in our post endpoint, we get an instance of

58:05 the login form that we can then go do stuff with.

58:07 If I show you a more comprehensive or complex example, this is big model here becomes big

58:13 form and this has a bunch more stuff in it.

58:15 So it has file inputs.

58:18 File inputs are one of the reasons we can't just submit, submit JSON because yeah, we

58:22 don't want to be part of encoding and all those things.

58:26 Yeah.

58:27 All those things.

58:28 Right.

58:29 And so here we have name.

58:30 We use bold again, as I have before to indicate required fields.

58:34 So we could, I don't know, I've got some Pydantic logos here that I'll use as images.

58:39 This one is multiple images.

58:41 So we can select multiple images, a date field in this date.

58:45 I've got a calendar picker.

58:47 Very nice.

58:48 So that's just input type equals.

58:49 That's just input type equals date.

58:51 Okay.

58:52 We have switches.

58:53 We have, and then you'll see here, we have size model, arrow width and size model, arrow

58:57 height.

58:58 And the point is that we're doing here, and these are integer fields, but the cool bit

59:01 is that they map to a nested Pydantic model within the big model.

59:07 What FastUI is doing internally is basically flattening this into one list of form fields,

59:13 which is then what we get rendered here.

59:14 I see.

59:15 So in your Pydantic model, you have a size object, but then in the form, it just has

59:19 the width and the height, the one after another.

59:21 Size width and size height.

59:22 Exactly that.

59:23 If I put a requirement or a restriction like min or max onto the field in the size model,

59:30 would that become a client side min and max in the form?

59:33 There's a PR to do exactly that.

59:35 Yeah.

59:36 Awesome.

59:37 We will get server-side validation as well.

59:39 And then we'll look at it for a couple of weeks.

59:40 So like it's, there's more to do, right?

59:43 But that's awesome.

59:44 That's really fun.

59:45 Yeah.

59:46 And then you'll see in uploads, we have some quite powerful things we can do here.

59:48 So we use the upload file, which is a starlet type, but we can also annotate it with form

59:55 file, which takes two optional arguments of what rule, what except to apply.

01:00:01 So that will both in the browser, when you open the...

01:00:04 Yeah.

01:00:05 When you choose a file browse dialogue.

01:00:06 Yeah.

01:00:07 It'll tell you what size.

01:00:08 You have a MIME.

01:00:09 So for people listening, you have the MIME typeset, not like an extension, but you have

01:00:11 image slash star, which means image slash JPEG, PNG, WebP, et cetera.

01:00:16 Right.

01:00:17 And that's understood by the browser and then by the OS to let you select files, but it's

01:00:21 also validated server-side.

01:00:23 So if someone goes and edits their HTML and submits a not image, the server-side validation

01:00:28 will check at least based on the file extension that it looks like an image and you get back

01:00:32 the bytes.

01:00:33 So you could also go do validation that the bytes are a valid image if you so wanted.

01:00:37 You could read the bomb, the mark that indicates the file type that's sometimes in these different

01:00:42 files.

01:00:43 Yeah.

01:00:44 If I submit this, but let's say, well, first of all, I try and submit this because we've

01:00:46 got server-side validation of which fields are required.

01:00:49 It won't let me submit if this file field is not completed.

01:00:52 And then I think if we put in name and we don't capitalize it in this case, we'll go

01:00:57 off and do the validation and come back and we'll say name will start with a capital because

01:01:01 I've implemented it.

01:01:02 Where's that validation?

01:01:03 Oh, I see.

01:01:04 That's a function that you write.

01:01:05 Right.

01:01:06 And just to prove the point, I've just written a validator in Pydantic, which says this must

01:01:10 start with uppercase.

01:01:12 And if I then went in here and edited that print out form, is that going to now clear

01:01:18 my form?

01:01:19 No, it's not, which is magic.

01:01:20 And if I submit that, you'll see here where I printed out the form, we got the different

01:01:26 file objects and we got the raw data all come through as the Pydantic model.

01:01:30 Yeah, that's really cool.

01:01:31 And so I love how even the custom validators in Pydantic, like Python code that you wrote

01:01:37 appears on what feels like client side, but is really server side validation run by React,

01:01:43 right?

01:01:44 Yeah, exactly that.

01:01:45 And so we'll do stuff like link checks and all the things you can do on an input client

01:01:48 side as well.

01:01:49 But of course, there'll also be enforced server side, which obviously if you're building anything

01:01:53 that is going to be exposed to the internet, you've got to do.

01:01:56 Yeah.

01:01:57 You should never, never trust what comes into your web app.

01:02:00 It's just put it online for five minutes and look at the log.

01:02:02 It's already trying, somebody is already after wpadmin.php, you know?

01:02:07 Yeah, exactly that.

01:02:08 And then the last thing I'll show, I know we haven't got very long at all, is authentication,

01:02:11 which I've just been working on now.

01:02:14 This is again, it's a simple form.

01:02:15 I'm just going to select an email, put in a random password and I can log in.

01:02:20 And in this case, I've logged in.

01:02:22 It just says who I am and how many people are logged in.

01:02:24 If I come back to this page, it'll show me logged in and I can do post requests to log

01:02:29 out.

01:02:30 And what it's doing internally is, and again, this is the kind of thing that would be lots

01:02:33 and lots of work to implement if you're doing it yourself, is it's storing in session storage,

01:02:38 the auth token, then adding it as a header where we do the fetch from the front end to

01:02:42 the back end so we can effectively store sessions that way.

01:02:46 Oh yeah, very cool.

01:02:47 Yeah, that auth token's coming in as a header item or being set as a header item.

01:02:51 Excellent.

01:02:52 Right, exactly.

01:02:53 Cool.

01:02:54 So yeah, I hope that we've done a bit of a whirlwind tour through FastUI and what's there

01:02:57 now and what I hope is coming up and the slightly philosophy of why I built it.

01:03:02 But yeah, I hope that was interesting.

01:03:04 It's super interesting.

01:03:05 And it's really early days.

01:03:07 I'm looking forward to two things, to see what people go do with it, what widgets and

01:03:10 stuff they build.

01:03:11 So can you drop in, like you said, a calendar or something awesome like that.

01:03:15 And I'm also looking forward to see what you all internally release in a couple of months

01:03:19 from it.

01:03:20 Absolutely.

01:03:21 And thanks so much for having me and letting me witter on about this random library.

01:03:27 Yeah, of course.

01:03:28 Good work.

01:03:29 It's certainly creative.

01:03:30 Maybe just give people a sense of, as we wrap it up, can they use it now?

01:03:35 Should they use it now?

01:03:36 Can they contribute?

01:03:38 Maybe they're interested.

01:03:39 What do you tell that crew?

01:03:40 I'd love people to contribute.

01:03:41 I mean, almost most useful is issues saying how you're using it, where it's working, where

01:03:46 it's not.

01:03:47 There is a bunch of people who've already submitted PRs and continue to do so.

01:03:51 And yeah, I think what works, works pretty rigorously and it's probably better implemented

01:03:56 and tested than lots of private code.

01:03:59 But definitely within internal uses, use it now.

01:04:01 And like I say, Pydantic is building things with it now.

01:04:05 So look, I mean, I give the open source guarantee that it's relatively safe, which is the guarantee

01:04:11 that means nothing.

01:04:12 But mostly because at the end, it's just defining how you build your UI and how you implement

01:04:17 your session authentication.

01:04:19 It's not having strong opinions about that.

01:04:20 So yeah, I think it's, I think it's the place where people should go and try it and give

01:04:24 feedback.

01:04:25 Excellent.

01:04:26 All right.

01:04:27 Well, thanks again for coming on the show.

01:04:28 Looking forward to talking to you next week.

01:04:29 No, just kidding.

01:04:30 Like two in a row, I suppose.

01:04:31 Looking forward to talking to you 2024.

01:04:32 Absolutely.

01:04:33 Have a good Christmas.

01:04:34 Thank you so much.

01:04:35 Yeah.

01:04:36 Thanks.

01:04:37 Bye.

01:04:38 This has been another episode of Talk Python to Me.

01:04:39 Thank you to our sponsors.

01:04:41 Be sure to check out what they're offering.

01:04:43 It really helps support the show.

01:04:45 This data is professional web scraping and a dataset marketplace.

01:04:49 If you need data and it doesn't have an API, check out talkpython.fm/brightdata today.

01:04:58 Take some stress out of your life.

01:05:00 Get notified immediately about errors and performance issues in your web or mobile applications

01:05:04 with Sentry.

01:05:06 Just visit talkpython.fm/sentry and get started for free.

01:05:10 And be sure to use the promo code talkpython, all one word.

01:05:14 Want to level up your Python?

01:05:16 We have one of the largest catalogs of Python video courses over at Talk Python.

01:05:21 Our content ranges from true beginners to deeply advanced topics like memory and async.

01:05:26 And best of all, there's not a subscription in sight.

01:05:28 Check it out for yourself at training.talkpython.fm.

01:05:31 Be sure to subscribe to the show.

01:05:33 Open your favorite podcast app and search for Python.

01:05:36 We should be right at the top.

01:05:37 You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the Direct

01:05:43 RSS feed at /rss on talkpython.fm.

01:05:47 We're live streaming most of our recordings these days.

01:05:50 If you want to be part of the show and have your comments featured on the air, be sure

01:05:53 to subscribe to our YouTube channel at talkpython.fm/youtube.

01:05:58 This is your host, Michael Kennedy.

01:05:59 Thanks so much for listening.

01:06:01 I really appreciate it.

01:06:02 Now get out there and write some Python code.

01:06:05 [MUSIC PLAYING]

Back to show page
Talk Python's Mastodon Michael Kennedy's Mastodon