
Joe Cheng - Shiny: Data-centric web applications in Python | PyData Seattle 2023
www.pydata.org Shiny is a web framework that is designed to let you create data dashboards, interactive visualizations, and workflow apps in pure Python or R. Shiny doesn't require knowledge of HTML, CSS, and JavaScript, and lets you create data-centric applications in a fraction of the time and effort of traditional web stacks. Of course, Python already has several popular and high-quality options for creating data-centric web applications. So it's fair to ask what Shiny can offer the Python community. In this talk, I will introduce Shiny for Python and answer that question. I'll start with some basic demos that show how Shiny apps are constructed. Next, I'll explain Transparent Reactive Programming (TRP), which is the animating concept behind Shiny, and the reason it occupies such an interesting place on the ease-vs-power tradeoff frontier. Finally, I'll wrap up with additional demos that feature interesting functionality that is made trivial with TRP. This talk should be interesting to anyone who uses Python to analyze or visualize data, and does not require experience with Shiny or any other web frameworks. PyData is an educational program of NumFOCUS, a 501(c)3 non-profit organization in the United States. PyData provides a forum for the international community of users and developers of data analysis tools to share ideas and learn from each other. The global PyData network promotes discussion of best practices, new approaches, and emerging technologies for data management, processing, analytics, and visualization. PyData communities approach data science using many languages, including (but not limited to) Python, Julia, and R. PyData conferences aim to be accessible and community-driven, with novice to advanced level presentations. PyData tutorials and talks bring attendees the latest project features along with cutting-edge use cases. 00:00 Welcome! 00:10 Help us add time stamps or captions to this video! See the description for details. Want to help add timestamps to our YouTube videos to help with discoverability? Find out more here: https://github.com/numfocus/YouTubeVideoTimestamps
image: thumbnail.jpg
Transcript#
This transcript was generated automatically and may contain errors.
Hi everybody, this talk will be on Shiny Data-centric web applications in Python and this talk will be introducing Shiny for Python and it's by Joe Cheng
A little bit of info about Joe Joe is the CTO and first employee at Post-It PPC formerly known as RStudio where he helped create the RStudio IDE and Shiny web framework along with countless complementary tools and packages Please welcome Joe for his talk
Thanks Vincent Today I'm going to talk to you about Shiny for Python a package for creating data-centric web applications in Python
This is an example of a pretty simple, typical Shiny app I'm going to go ahead and click it and hopefully show you the live version On the left we have some parameters that I can use to affect the graph On the right, this is using Seaborn and on the back end it's AppCandice or Polars or something, I don't remember and on the top here I can show some big numbers and my colleague who created this example app wanted to make sure that I clicked on the penguins so you can see the lovely art by Alison Forst
What is Shiny for Python?
So, Shiny is, as I said, it's for creating interactive apps and dashboards in Python and we'll get into some of the different applications today But I want to emphasize, because... How many here have heard of Shiny before? And how many of you have heard of Shiny in the context of R, not Python?
I want to make sure that it's clear because I've gotten this question Shiny for Python is not a wrapper around Shiny for R This is not like you have to install R to use Shiny for Python Shiny for Python is a ground-up reimplementation of Shiny in PurePython
and it was designed primarily with data scientists in mind and that has a couple of implications Number one, we don't expect you to have web development skills You can do tons and tons of stuff in PurePython and it's based on this reactive programming approach to interactivity that we specifically chose because it's easy to get started with and relatively hard to make mistakes
On the other hand, I personally have been creating websites and web applications since 1996 It would be really frustrating for me personally if day in and day out I was working on this web framework that felt lowest on the denominator in any way or that it had artificial guardrails So if you do have web development skills you can fully leverage them to customize or extend your Shiny apps and it seems like even in data science more and more people seem to be picking up some of these skills
And the same reactive programming paradigm that is so easy to get started with it's also powerful and flexible and deep as I hope to show you today
Anatomy of a Shiny app
Just to get concrete here this is what a Shiny app looks like in Shiny for Python This is probably the simplest app This is like a Hello World app basically Every Shiny app has two main components There's first the user interface and this is Python code that generates HTML to send to the browser And in this case, it's going to look something like this
So in this case, we have an input slider and an output plot And this app UI variable that it's creating is literally just HTML Like if you were to print that out of Python, that's what you would see
And the other component is this server logic that runs on the server at runtime and it provides the interactivity of the app In this case, if the user touches the slider and moves it to a new value this input.n is automatically updated and this entire function will run to generate a new plot that is sent to whatever spot is designated in the UI by output underscore plot there
So that's the basics of how a Shiny app is built At the bottom is just a single line to create an app object and assign it to an app variable
And this is what your user experience will be like as a developer Using VS Code here, we have a Shiny for Python VS Code extension So you can just click this play button here if you have a Shiny app on the screen And it will run the Shiny app at the bottom putting you in the right virtual environment and things like that And at the right, the application will appear And as you save changes to your application Python code it will go ahead and reload automatically As you would expect in 2023 for a web framework
So let me show you a slightly more complicated example than just that hello world In this example, we are using the Astropy astronomy package for Python to create a tool that helps astronomers know when are the best times to look for these specific celestial objects that they're interested in observing This will show you when they'll be brightest in the night sky depending on what day and what location on Earth you're in
And I'm going to show some code here Don't worry if you don't try to ingest it all I just want to point out a couple things about this kind of code So in this Shiny UI, we're using some additional features First of all, this is an h3 tag In HTML that means heading level 3 So if you know HTML and you're familiar with HTML tags you can directly access them by using these Python functions that wrap the equivalent HTML tag
You can use markdown In this case, we have a link in the middle that's using markdown syntax And we can have rows and columns that have varying widths We have outputs We have inputs And if you put all that together, you have a UI that looks like this
And one other thing that I want to point out When I zoom out, there's sort of a shape to the code Because it's nested functions, there's sort of a shape that the indentation gives it And there's two big chunks here One for the header and one for the body And I really love this property that the shape of the code is reflected in the shape of the UI And this is true in sort of a hierarchical way So inside of that body, there are two columns And you can see the shape of those columns reflected in the shape of the code And as your apps get larger and more complicated This is a really beautiful property Because it means it's easy to find your way to the specific spot in your complex UI Where you need to make changes
And I really love this property that the shape of the code is reflected in the shape of the UI
Shiny vs. Streamlit
Okay, so we announced Shiny for Python about a little less than a year ago And the news made the rounds And on our data science subreddit I think we had a pretty typical range of reactions Some people were really excited But other people were like this But it's just so easy to throw something up with Streamlit
How many people here have heard of Streamlit? Okay, how many people have used Streamlit? Okay, so a few of you
And Streamlit has this reputation for being just so easy And I want to examine that, unpack that a little bit So imagine that you have a script.py A totally normal linear Python script that is doing some data analysis Let's say you're loading some data You are maybe cleaning it a little bit And then you're previewing a pandas data frame and then plotting it The promise of Streamlit is that you can take pretty much that exact script Sprinkle in some Streamlit to add some UI And boom, you have now an interactive data product or what have you
And contrast that to Shiny Which, if you've never seen Shiny before, even what I just showed you Clearly, Shiny wants you to put code in the places where it tells you to So it is a different approach And this approach that they have of being able to write Streamlit apps In the same way you write Python scripts There's a very specific way they make this possible Streamlit's architecture allows you to write apps the same way you write plain Python scripts To unlock this, Streamlit apps have a unique data flow Anytime something must be updated on the screen Streamlit reruns your entire Python script from top to bottom
And let me be clear, it is easy I mean, for simple Streamlit apps, it is unbelievably easy You could learn Streamlit by accident You could write a Streamlit app falling down the stairs I mean, it is really, really easy And they also have really nice-looking output I mean, it's pretty hard to make a bad-looking Streamlit app
But this model also has limitations that are quite obvious And especially with the early versions of Streamlit You had this pretty slow performance Because it's always executing the entire thing again and again And pretty soon you need to start being pretty deliberate about caching values And you have pretty limited opportunities for interactivity Other than changing parameters, the whole thing kind of rebuilds
So Streamlit added some capabilities called caching, callbacks, and session state And as people develop in their Streamlit journey They find themselves relying more and more on these techniques And this is where I sort of, I'm out, you know The combination of this beautifully elegant top-to-bottom execution model Plus these other features, I think this combination is actually quite dangerous
And I'm not going to elaborate too much more on this This is not a talk about Streamlit But I just want to make it clear that this is not something that I made up I came to this conclusion by looking at the feedback that Streamlit's most rabid fans were giving them So in the big picture context, I see one critical issue for Streamlit The top-to-bottom rerun on every interaction paradigm Maintaining state becomes really difficult And there are just multiple examples where people found this model At first super simple, and then ultimately kind of painted them into a corner
So what we've tried to do with Shiny and this reactive approach Is to have a paradigm that's both easy to get started with and it scales It scales as the complexity of your apps scale It scales as the kinds of things you want to do to extend your apps increase And over the last 10 years, as Shiny for R has proliferated on these same ideas of reactivity We've seen people build rather complex data apps indeed
And a lot of the time, if you talk to our users and customers Who are getting the most value out of Shiny They're often building rather complex, not just a simple dashboard Not just a simple model demonstrator But really using Shiny for those things, yes But also integrating into critical workflows
And this idea of reactivity that was really the kernel that started Shiny Over the last 10 years, it's been unbelievable to me How fertile this ground is for new ideas That these small reactive primitives that we've been working with since 2012 Really can be combined in all these interesting ways And features like this just sort of fall out left and right
And even after 10 years, last week getting ready for this talk My colleague Winston Chang and I discovered a new way to use reactivity To interact with async Python generators In a way that made, you'll see, one of our demo applications possible
Demo: ChatGPT integration
So now I'd like to launch into some demos And it's 2020 for me, what is Tech Talk Without some kind of large language model demo, right? So this is a package that Winston has been working on That basically makes it easier for him to scratch his own itch Of playing with OpenAI's chat2BT API
So this is a super simple Shiny app that you can see here We're importing this cat module, that's new And with one line of UI and one line of server And this is where I hope the API works well today
So, okay With one line of UI and one line of server I have a chat2BT interface So I have like, why is the sky blue? And the fact that this text is streaming in This is that thing that we were playing with with async generators You know, it's chat2BT, so why is the sky blue as a wrap?
So really easy, but It's not that interesting if we're just inserting an island of chat2BT Into a Shiny app, right? What we really want to do is be able to interact with And mess with the conversation between chat2BT and the user
Winston recently bought a Samsung induction range He really wanted me to tell you guys He bought a fancy new Shiny induction range And this range is pretty new And chat2BT 3.5 is only current up to September 2021 Something like that So, despite having a PhD He was not able to figure out how to set the time On the clock of his new stove
What this application lets you do is Take a PDF, so in this case the Samsung induction range User manual And you upload it to this document And now it's indexing, it's generating embeddings And when I ask a question, it's going to send a context to chat2BT So I can say, how do I set the time on the clock? And it gives me a list of steps Okay, great, and now our clock can stop flashing at 12
So, in this example We had to change the payload that's being sent to chat2BT Without having that interfere with the user experience So that's one thing that this package lets you do
And then one more chat2BT example, and then I'll move on So this one's a little different in that there are two chat2BTs That I've embedded in this one app And it's really fun to, you know, sort of compare As you have one conversation, you can talk to another model And ask it different things But let's play 20 questions
And this app has this mode where you can have these two models talk to each other So let's play 20 questions You guess first Go ahead and guess And I can click this converse with self And every time a response comes back from one of these conversations It'll be directed to the other side So now we are watching chat2BT play 20 questions with itself Is it an object? Yes, it's an object Is it commonly found? Yes There's a lot of yeses, this is a little bit suspicious I should have turned the temperature up, I guess Can it be used for cooking food? Yes Can it be used for cooking food? Is it made out of metal? This is some BS, what is with all... Honestly, this doesn't usually happen, this seems very rigged Is it a frying pan? Oh, it is a frying pan, so...
Yeah, you never know, you never know what's going to come out Yesterday when I tried this, it was just smiley emoji And that was, it was that recursively Alright, that probably cost me like $2
So this package is available, this QR code It's super, super wet cement I mean, like, I think this has existed for like a total of four Christmas days now So definitely, you know, API can change and things like that But super fun to play around with
Demo: Hand-tracking with reactive smoothing
So for my next demo This is using a demo that, an example that came from Plotly So this is a Plotly widget on the right here Showing a 3D visualization of Brownian motion Now Brownian motion is like the random motion of a particle on a surface Or in a volume of air or something like that And I can hit new data here to generate new samples, new random samples And some of these look really cool, and some of them Like this one, it's a little harder to see what's going on Just because of the random angle that the camera happens to be at Now because this is Plotly, they have this feature where you can click and drag And that's cool, right
But just for fun, for this example, we're going to do something different So I'm using the Google Media Pipe library to track the position of my hand So Google's doing all the heavy lifting, like detecting the length of marks on my hand But Shiny is calculating a normal vector shooting out of my palm And then using that to determine where the camera angle goes And the reason I show you this, besides, you know, just that's kind of fun Is this feature here, this smooth tracking So if I turn this off, this is what this demo originally looked like And, you know, when I got this working, I was like, oh my gosh, this is amazing And my son is a senior in high school and is going to be a computer science major next year I was like, come over and come look at this And he was like, why is it so jittery?
So, yeah, but, you know, it's a good question Like, why is it so jittery? And it's jittery because sensors are jittery, right But I thought it was an interesting question Can we make it not so jittery? So we tried a couple of things We tried only registering movement if it was over a certain number of pixels And that was like a complete mess It was super stuttering and slow And then we thought, like, what if we just average over the last five samples that we collect And that's the approach here It's just a simple mean over the last five samples And it works great, super smooth
What's interesting about this is It took about 10 minutes to implement that smoothing in 30-something lines of code But what this is, is actually not a smoother for this app This is a generalized smoother for any reactive value or source in Shiny So that means that any kind of input that you have in Shiny that's fast and noisy You can apply this function, tell it how many samples you want to smooth over And provide your own algorithm for how you take n samples and collapse them into one In my case, I was doing a mean, but you can do whatever you want With this short snippet of code, we have generalized smoothing available in any Shiny app you can use
This is a generalized smoother for any reactive value or source in Shiny So that means that any kind of input that you have in Shiny that's fast and noisy You can apply this function, tell it how many samples you want to smooth over And provide your own algorithm for how you take n samples and collapse them into one
And that's kind of what I was talking about We keep discovering these new applications of this technology called reactive programming
Shiny Live and the UI editor
Just a couple more features I want to talk about One is Shiny Live Shiny Live is the combination of Shiny and the power of WebAssembly Via the pretty famous at this point PyDive project So if you haven't heard of it, PyDive is Python running inside of your web browser using WebAssembly
And what this lets you do is have an experience like this Where we have this web page loaded And there's actually nothing behind this web page other than HTML, CSS, and JavaScript There is no server running Python Python is running entirely within the browser And this is just showing a real-time CPU graph Well, to be fair, one thing you cannot do in the browser is monitor the host computer's CPUs So this is fake data But if you imagine some other streaming data source, the same kind of techniques would apply We have a Canvas-style data table at the bottom
And we can change this color palette to have different color maps And this one is not awesome So let's go ahead and remove that as an option So we can come here and delete this And if I press play, now it is reloaded and my update has taken effect So pretty nice to be able to just come to this web page You don't have to install Shiny on your mobile or anything You can just start playing with Shiny through the shinylive.io website And if you like what you've done here, you can even share it through a URL
So if you want to send this to a friend that you want to see the code, then you can use this link And they have basically the same editing experience as you did Or you can click here and say, no, I want this just to feel like a full-on application And it hides all the Chrome and just shows the app
So the nice thing about this is that the computation now is all happening on the browser So you can actually use this technology to deploy Shiny apps to any static web host You can put it on GitHub Pages or what have you instead of having to pay for Heroku We also have free hosting, but if you wanted to put it on any static web host, you could
And you can also easily embed these kinds of Shiny applications in Quarto If you haven't heard of Quarto, it is a way of stitching together narrative through markdown And computations and outputs of computations all together in beautiful documents My colleague JJ O'Leary will be talking about that later this afternoon And what this lets you do is it lets you combine these applications Either bare like this or with a full editing experience directly into your documents and reports Super easy to do
And we like that feature so much that we actually use Quarto to build our documentation website So when you're learning Shiny, all of our examples take place in these little editors And all of this is using Quarto and Shiny Live
One more feature, this is not available yet This is something that we're working on, but I was really excited about it, so I wanted to at least give you a preview We have a Shiny UI editor that's being developed that is a way to drag and drop your way to creating Shiny UI So instead of writing the UI code that I showed you with nested function calls You can use controls on the left, drag them onto this surface in the middle And then use the pane on the right to modify properties And all this is doing is just writing the same code you would write So the end result is not a lot different than if you were to write it by hand
So you can change some properties on the slider here So what you're seeing in the middle is just sort of a wireframe version of the application It's not high fidelity, but in the lower right it's rendering a preview that is showing the live application And you can click it to see what your application actually looks like So still early days for this thing, but we expect to be rolling it out in the coming months And we're super excited about making it easier for people to create Especially if you're building dashboards that have a bunch of rectangles on it To get the spacing exactly right and to get the right proportions It's one of those things that's easier when you're dragging and looking at it in real time Than writing the code
Okay, that is it for me If you are interested in writing powerful reactive web applications I highly encourage you to go to shiny.plus.co.uk We have examples and lots of articles and reference documentations there That QR code is to the main website And if you are interested in the source code of my examples minus the chat ones They're at PyDataSeattle2023 And maybe in the middle of questions I'll switch over to show the other slide again So yeah, thank you
Q&A
So I tend to leave plenty of time for questions Does anyone have any questions? Yes, in the back Hi, I've never used Shiny, but I was just wondering if you could characterize If I have some data on the back end that I want to reference or plug into this Suppose I have a file that has a couple hundred thousand rows of data What should I think about, or do you have a capacity?
Yeah, sure I think the question was if you have data on the back end that's maybe a couple hundred thousand rows Or really, I think the question you're asking is how do you get your data into this thing And what size limitations do you need to worry about So you can use any sort of Python code you want to load your data And our example apps use Canvas and Polars and DuckTV And pretty much it's up to you how you want to load your data
Now there are a couple things that are worth talking about as far as scalability and things like that go Number one, as a general rule, your data stays on the server So if you're looking at a bunch of plots you made in Seaborn and that's it Then you could load gigs of data and none of it is transferred over the wire Just the actual outputs that the user is viewing And that may sound obvious, but that's not true for all Python data science frameworks
Now I think the main thing that you'll have to worry about is, number one, is memory consumption So in order to get good performance, you want to not be going back to reading a huge CSV Every time the user kind of touches anything So by default, Shiny has these reactivity features Actually on the screen here it says React and Calc This is sort of a way to do very smart caching of your data as it changes So in general, it'll cache the last copy, like the current copy of your data that you're displaying So if you're loading a gigantic data frame and that is the result of your React and Calc expression Shiny is going to hold one copy of that in memory If you do a bunch of aggregation on it before you return it, then Shiny will just hold the aggregated values Which could be much, much smaller
And also, I think as your data gets bigger, just like anything in Python data analysis You start to look at sort of out-of-memory things You start to look at things like .db or using a full-blown database or an OLAP system or something like that And maybe not just loading CSVs into memory
I'm curious, how easy was it to move Shiny over to Python? Like, Python has been used for web development for a long time compared to R I'm just kind of curious if you have any feelings on that
Yeah, how hard was it to move Shiny over to Python? I think it was one of those things that seemed really scary until we started And then it went very quickly And that includes having to really learn, like, Python's type annotation system Wasn't something that existed the last time I really did any real Python And that was something our whole team had to pick up and get good at But, you know, I'd say like 90% of it was surprisingly fast And then every once in a while there was something that, like Creating the reference documentation took an ungodly amount of time So there were, like, surprising things that ended up taking the other 90% of the time
What would be the difference between using something like Shiny and moving it to Qualys-Dash? Because we're designing it off what it's going to choose to be So, you know, what were your expectations?
Yeah, I was expecting that It took three minutes to get to that question No, no, no, it's a really good question And I almost addressed it in my talk And then I just thought I'd leave it for a question Well, every web framework has its own opinions about what's important And we all make different payoffs And in the particular case of Dash The most opinionated thing they did was they made the server stateless And that means that there is no memory in Dash Between one invocation of a callback and another So it's kind of like, to me, that has always puzzled me As the choice that they made Because it introduces such annoying limitations for the app author And really mostly has a marginal benefit For the people who ultimately have to deploy the app
I actually was curious about this I was going to make this assertion that it has this big downside And fairly marginal upside And I think we have a lot of customers that use Shiny for R And Dash for Python And I don't think anyone has ever said Oh, and we love that Dash is serverless I mean, stateless It doesn't matter for the vast majority of especially data-oriented applications
But listen, I'm here to learn So if you are a Dash user and you love Dash And I'm wrong and you love the stateless aspect of it Then absolutely please come talk to me at the deposit booth But I will say, I think when people start to realize How much state is being transferred to the server Every single time you touch anything Like if you upload a CSV You're really just holding it in the client And every single output that renders Every single time they render You have to send that data to the server In every XHR call And that's just a really surprising tradeoff to me
So in fairness, Dash Plotly has a page about Like they know this is a problem Like here are all these mitigations But to me, that exact problem that they have workarounds for Was the heart of Shiny Like the heart of Shiny is that you have this state That you're going to want to use again and again As you tweak through the different possibilities of your analysis And what we treated as core They treated as sort of a little more of an afterthought
Maybe this is kind of piggybacking off of her question But we use Bokeh a lot, like a Bokeh server And we have that in the Flask framework Do you have this ability to change To embed the server Because we have this huge production of Bokeh in Flask
Sure, sure, sure Yeah, so the question was At your work, did they embed Bokeh Or really integrate Bokeh applications Into larger applications that are written in Flask So almost Shiny is not based on Flask But based on the newer ASGI frameworks So it is based on Starlet or FastAPI You've heard of that So you can combine Shiny with FastAPI applications In exactly the same way that you can combine Bokeh with Flask
That being said, for existing Flask applications The other way you could go, which people do with Shiny for R Is to aggregate at the proxy layer So you would run an Nginx server in front of both servers And then use that to basically map Shiny onto Your Shiny app onto a certain URL path I'm making it sound more complicated than it is
So if you are running a stateful server How do you handle multiple people accessing Shiny at the same time?
Yeah, so the question was If we're a stateful server How do we handle multiple people accessing the server at the same time? And that is an excellent question There are a couple ways that you do that So let me first talk about multiple people hitting the same server Or the same Python process
So this server function Is actually invoked once per visitor Or once per, we call that a session But it's like a browser tab, basically So each visitor that arrives Gets their own copy of this input-output in a session So everything that you do inside of this server function Is isolated to that one user But a really interesting consequence of this architecture That I really love Is that you can put things here So you can put reactive objects here And then they're actually shared by all users So you can decide what things are global What things are specific to each user
Now the other question you might be wondering is If you have multiple servers in a cluster How do you, you know, there's something in memory On a particular server How do you make sure that it's routed? So for that we just ask that you turn on sticky load balancing Which every load balancer has that feature And pretty much pops off
So when you share Shiny apps Is there any obfuscation from underlying data That comes through? So if you're sharing apps outside of your organization Or a conference or anything like that Is it easy to create some stack And get all the underlying data Or is there some security?
Oh man, can you imagine if I answered Like yes, it's easy to get at the underlying data That would be real bad No, so for Shiny It is, at the end of the day, it's a web application So the messages that are going back and forth over the wire Are the inputs and the outputs The underlying data, the underlying code Remains locked away on the server The one exception to that is this Shiny live mode Where everything's running on the client Well in that case, everything's being shipped to the client So if you have hard-coded a password Into your Shiny application And then ship it via Shiny live to the browser Well, yeah, you've made a mistake But if you host it any of the traditional ways Where Python is running on the server And the front end is just showing pictures And giving you inputs Then everything is perfectly safe The same way it would be in Flask The same way it would be in Django Or any other web application framework
So you're comparing it to Flask and Django, FastAPI Is the CICE, like this looks like really From a developer's perspective Super easy to get up and running And the logical next question is Okay, now I need people at my organization to use this I need it to get deployed I need it to get updates, improvements Is that kind of standard? Or are there any additional considerations Beyond the typical FastAPI development and deployment?
Yeah, yeah, you sound like someone who works for a living That's a very practical and important question So the question was Yeah, this seems great for whoever is writing the application But when it comes to the time to deploy it And integrate it into CICE pipelines And keep it up and keep it stable Is there anything that you need to be aware of? So in terms of the deployment It feels pretty much like a typical FastAPI type app
I'd say if you write a traditional Django or FastAPI type app The testing can be easier Because really what you're writing For most of those sort of lower-level web frameworks Is a series of endpoints And with Shiny, all this interactivity This is happening over a WebSocket There's no reason why that's not inherently testable But most people in most organizations Do not have a lot of experience Testing WebSocket-based applications So I will say we have been using Playwright If you use Playwright or Cypress as testing frameworks They work awesome And Playwright will even let you inspect the WebSocket traffic As it goes through
But yes, if you have people that are used to testing Django apps Specifically the testing aspect And also the load testing aspect It's probably going to throw them for a loop for a little bit But other than that I mean, to be honest The turnaround times on building these kinds of apps For people who know a little bit of Shiny It is so dramatically different Than what it is for using And by the way, the same is true for Streamlit and Dash You were talking about a different order of magnitude Of velocity Versus using sort of these lower-level frameworks That, you know, people get That there are going to be these kinds of tradeoffs Where the wires are not quite as visible And you can't instrument them quite as well
One final question Or no, you guys are out That's fine Thank you very much

