Rio: Web apps in pure Python
github.com
github.com
So, I am the target audience of this. I have a LOT of experience writing tools and automation and that is where most of my Python knowledge comes from. I am not an expert Python programmer, but I am competent.
But sometimes, I have an idea for writing a web application that would greatly improve my day-to-day life in some way. I know exactly what I want it to do, I know exactly what I want it to look like. I have already designed the API in my head, and could probably write the bulk of the Flask code in under an hour. Maybe a couple of hours if you want tests. But what I DON'T have is the time to learn is the vagaries of HTML+CSS layout and internalize the Great Lessons of the last 20 years of JS development history.
I have consciously stayed away from (non-trivial) web development because the tooling and patterns change almost daily. But the old stuff is not replaced, it is simply bolted on top of. And you have to know the WHOLE stack in order to troubleshoot most any part of it. Waking up one morning and saying, "I know a fair amount about computers, I want to write a web application," is just about as fanciful as saying, "I know a fair amount about airplanes, I want to design a jet engine."
Rio devs, thank you for releasing this as open source. I look forward to checking it out. Even if it doesn't pan out for me, I appreciate that you took a crack at it.
Just think of how many man years we could have saved if we did this.
The simplified layout system comes with its own inspection tool built into the dev version of your app so you get productive in an hour or so. They really got that part right in my opinion. As soon as they make custom components done I’m gonna discuss adopting it for our internal tooling.
I am not affiliated with them btw.
I can't wait to hear your feedback
That is just plain wrong. And that comes from someone who stayed from web dev for the same reason. Nowadays it’s vite/esbuild and you’re good to go.
And you don’t need any web framework to come up with basic ui.
touch index.html; touch styles.css; python3 -m http.server
And you’re good to go.
> "I know a fair amount about computers, I want to write a web application," is just about as fanciful as saying, "I know a fair amount about airplanes, I want to design a jet engine."
This analogy makes no sense.
You do not need a framework if you really know CSS and HTML5 well, but that is exactly "knowing the whole stack" - which was the parents point.
You’re describing more than 10 years of evolution here. That’s hardly daily.
These days it’s npx vite build, what’s there to learn?
I do back end web development, but need to be able to build and run the whole thing locally. I've been through webpack, and grunt, and.. um.. something before that. And throughout it all, I have a make file that has targets for 'clean', 'build', 'NOTEST=true' (to prevent tests from running), etc... specifically because I find it super frustrating when we need to move from one build system to another, and trying to remember which one _this_ project is on, and how that one does each thing, etc.
So every time we add (switch to, but really add) a new build system, I update the Makefile to be able to build with that system, and then just use make to build everything and completely ignore what's doing the actual build :)
This may have come along at exactly the right time. I'm kind of interested.
I swear, HTML/CSS + Flask + HTMX gets you so far these days. Then, you can throw in some AlpineJS for any inter-element interaction you need and build a responsive SPA without almost any JavaScript.
We've been getting a lot of reactions from people being surprised how quickly they can create Rio apps after just a few hours, when previously creating UIs was always a major roadblock for them. Seeing these reactions has been extremely rewarding.
These type of condescending comments really scream "I'm not even a web developer but here's my strong opinion as someone who only makes toy front ends to demo my data work"
But I am a fan of alternative approaches to the typical stuff just for the fun and learning aspect of it. I'd never come on here and be like "oh well that's cute, but it's useless, why can't we just x".
For example I think Imba is pretty cool and I've used it for a couple throwaway personal projects just to give a spin, but I'd not use it at work.
I don't see why you couldn't with Alpine.
Yeah at some point you may need a more sophisticated solution but plenty of projects don't need React. This very forum you're using is just a very simple vanilla js file.
And they were terribly unperformant, bug ridden, messes of spaghetti that I wouldn't wish on anyone in the year 2024. Things evolved past that for a reason.
I've seen way more bloated React/Angular SPA apps than the typical PHP/jQuery Web 2.0 from back in the day.
I was there, it sucked
You need to spend time learning how it works, what are it's limitations and what not.
The newer it is, the fewer components, help and support you have at your dispose.
I don't like these frameworks because it tempts people to learn something that isn't going to get mainstream adoption.
We already have to be careful when choosing a framework like React, vue, svelte etc...
Are you building a side project? You probably should just do it with what you already know, it's gonna be faster and probably better.
Not saying we shouldn't try new things or build new ways of doing stuff, but in this case you are not really running your python code on the web, your running compiled js,html and css...
I much rather choose something that allows me to write vanilla js with some extra features like signals.
Let me migrate my current project into the new framework and see what the experience is like. Let me hack some stuff together for fun, only then I'll consider the framework.
They are everywhere in JavaScript and I couldn't imagine my day-to-day without them!
For a person with zero front-end knowledge, it's a game changer.
const f = (x, y) => {
const z = x + y;
const w = z * 2;
return z - w + x;
};
In Python, you cannot do this: f = (
lambda x, y:
z = x + y;
w = z * 2;
return z - w + x;
)
Instead, you need to pull it out into a def: def f(x, y):
z = x + y;
w = z * 2;
return z - w + x;
Sometimes, this is no big deal. But other times, it's damn annoying; the language forces you to lay out your code in a less intuitive way for no obvious benefit.```f = lambda x, y: [ z := x + y, w := z 2, z - w + x, ][-1]```
* That version does look strange, as it uses a list in order to get that last calculation. But I often use lambdas to check results in parametrized tests, and they naturally spread to multiple lines without the list hack since they're chains of comparisons.
Yes, it is, it should, and that's exactly the point. It'd look janky even without the `[-1]`, and this is what the core devs are trying to protect against. Lambdas are anonymous functions meant only to be used in places where expressions are valid, such as function parameters and return values. There's even a linter warning if you assign one to a variable. All to help reduce the creation of janky-looking code, and that's a huge benefit for most developers.
Imperative programming only gets you so far.
Maybe this is a sign that people are using Python for grander things than it was designed for?
At the end of the day though there's really nothing to prevent you from creating janky code. Heck I saw a wild hack a couple weeks ago that allows for the creation of arbitrary custom syntax with pure Python, so you could create a multi-line lambda if you really want to that badly. But the widely adopted conventions exist for a reason.
Being unable to position it inline is the problem.
You might not see the benefit, but many do. It prevents Python from being a good functional programming, for one thing.
def outer(a):
def inner(b):
return a * b
return inner
Though slightly longer, for most developers, it's still more grokkable (and related stack traces better) than: def outer(a):
return lambda b: a * b
A very large part of Python's design is to emphasize readability for the majority. I still remember how long it took me to wrap my head around this "lambda thing" that I'd see pop up ever so often, even after a couple years of using Python. I eventually got fed up and took some time to really get to understand it. This shouldn't have to be the case for everyone reading random code.Python is a primarily OOP-based language with functional aspects. And the design decisions that went into it are what makes it so popular today. It's not Haskell or Lisp or any of the other many that the majority avoid due to language complexity. Don't try to make it into one.
[0] https://www.artima.com/weblogs/viewpost.jsp?thread=147358
He's saying exactly what I said: that parsing (or more precisely lexing) makes the problem complex, because Python uses indentation semantically. He then rationalizes avoiding the implementation complexity with a gut feeling: "But none of that takes away my gut feeling".
And the really ironic thing is that we wouldn't even be having this discussion now if not for this focus, because Python wouldn't have gained such popularity to the point it's also attracting more folk who would destroy what makes it so popular in the first place.
I'm not trying to put words in his mouth (I'm pretty sure I delineated his direct quotes with quotation marks). But I saw him write multiple paragraphs about the complexity of lexing multi-statement lambdas in Python due to its whitespace sensitivity, and then conclude that the user facing interface must necessarily be complex too, which just feels fallacious to me. If the complexity of the implementation doesn't factor into the design then why go through so much effort to communicate how difficult it is to lex? He compares the implementation to a "2000 step [...] infinite-dimensional" mathematical proof.
I just fundamentally don't buy the argument that one statement in a lambda is fine, but two is dark magic that needs to be removed from the call site and quarantined in a separate def, and I think if the implementation were simpler GVR wouldn't have been so diametrically opposed to the feature. Even if he outsourced the "puzzle solving" to an external contributor, no one enjoys the increased maintenance burden of a complex implementation.
Anyone who's ever written customer facing code knows what it's like to receive a seemingly simple feature request that's actually difficult to implement because of prior architectural decisions, and the "gut reaction" is to convince the user that the feature itself is bad. I hate to invoke comedy but this reminds me of the microservices meme: https://www.youtube.com/watch?v=y8OnoxKotPQ
Bit of correction: no statements and a single - arbitrarily complex - expression. An expression can be naturally delineated by parentheses; a statement stands on its own. End of the day, support for statements in a lambda would lead to a need for new symbols. Yet another thing that the user has to learn and remember, whether they're a professional software developer using the language regularly or a biology student using it for part of a one-off project. Again, the outcome of those decisions is clear today, given the general standing of the language.
It's a jab towards mathematicians in the context of criticizing a language proposal. He's comparing the complexity of mathematicians and their 2000 line proofs to the complexity of allowing statements in lambdas. He explicitly calls the proposal a "Rube Goldberg contraption".
> Bit of correction: no statements and a single - arbitrarily complex - expression.
I phrased it as a dichotomy between single and multiple statements because in many languages there's the concept of an 'ExpressionStatement', which is a single expression that acts as a statement. This makes the boundaries between a single statement and an expression somewhat murky. In JS for example the MDN docs have this to say about ExpressionStatements: "Apart from the dedicated statement syntaxes, you can also use almost any expression as a statement on its own." [1] GVR himself calls it "the problem of the multi-statement lambda" rather than "the problem of the statement lambda".
I don't want to get bogged down in pedantic debates about terminology though. I completely understand how it works, and said in my very first reply to you: "but it's nice to not be limited to expressions".
> End of the day, support for statements in a lambda would lead to a need for new symbols.
All it would require is a newline character. He calls this out in the blog post: "If the double colon is unpythonic, perhaps a solution could be found that uses a single colon and is still backwards compatible [...] I actually have one in mind: if there's text after the colon, it's a backwards-compatible expression lambda; if there's a newline, it's a multi-line lambda; the rest of the proposal can remain unchanged. Presto, QED, voila, etcetera."
There's absolutely nothing complex about allowing statements in lambdas from a user interface perspective (all of the complexity is in the implementation). Almost every modern language has support for this feature. Even Golang, which is perhaps the epitome of simplicity — the language that fought tooth and nail against generics, and doesn't have a ternary operator (or inline if), or string interpolation — supports defining inline callback functions with statements. There are even whitespace sensitive languages like CoffeeScript that bit the bullet and don't impose any restrictions on lambdas. The simplicity argument just feels really weak to me. At the time that blog post was written a Python user couldn't add a print statement to a lambda to debug their code. How in the world is that simple for biology students and people writing one-off projects?
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
FTFY.
I think the term you mentioned was there at the start but has since been removed and React is licensed pure MIT since 2017.
The primary advantage is that the built in set of components is pretty powerful (e.g. a real table view), everything runs server side, the Python can be JIT compiled, and from the user's POV it still feels like a web app (e.g. zoom is respected). You can "shell out" to Javascript if needed, you can use Java libraries. The JPro website is itself a JavaFX app running as a web app. Also there's a visual UI builder that's decent (and free).
Primary downside beyond just the obscurity of the stack (same problem as for Rio), is just that JPro is a commercial solution. But then you get commercial support and bug fixes in case you need something special or hit an obscure rendering case.
None of the python->web projects have this.
---
For me personally -- and I'm guessing for a bunch of other HNers -- writing full-stack web apps strictly in python is a non-goal.
I've settled on a comfortable (for me) stack for smaller projects that need python on the backend that combines:
1. Litestar (or another lightweight HTTP framework of choice like flask, etc.)
2. HTMX
3. htpy.dev (an in-python HTML builder)
4. Custom web components implemented in a plain-old JavaScript ES6 module loaded directly by the browser
A typical project only needs a handful of components. HTMX and htpy.dev both play very nicely with web components.
When I want zero build steps, I write plain JavaScript + JSDoc comments. JSDoc is... okay-ish, but it ain't no typescript.
If I need a database, I'll grab SQLAlchemy. I wish there were a mature lightweight solution here; maybe Tortoise ORM will get there soon?
There's nothing in this stack that couldn't strictly be done in javascript-land. JSX syntax with HTMX is pretty great and much better than any in-python HTML builder. But often my projects have other requirements (like ML) where python is, at least today, inevitable.
With the stack above, I typically write small classes that derive from HTMLElement and implement a couple key callbacks (usually, connectedCallback and disconnectedCallback). In those, I typically (a) initialize state by reading attributes from the DOM and (b) configure event handlers. Pretty simple.
That's... about it. I'm templating elsewhere, so I avoid using web component templates. And the less I think about the shadow DOM, the better.
For this, the MDN documentation on custom components is enough.
[Peewee ORM](https://docs.peewee-orm.com/)
https://github.com/rio-labs/rio/blob/41a6bb828c2e20eb7fdc5c6...
The way I see it is building apps somewhat similarly to SwiftUI is actually a pretty good idea. If you have established rules for how each container expands or fills its content you can build a great web app development experience without getting down into css and html explicitly. Just Vbox container Hbox container text container etc. I can certainly see a niche for this as it is a different style of UI development.
I’ve never been great as a UI designer so doing it in the traditional web stack has always been even harder but I’ve found that with SwiftUI I can usually get 90% of a good look very quickly.
So, something like this where I'm writing pure python for my web components could really save me a lot of that churn time, not to mention that many of my coworkers have absolutely no JS experience. I have an upcoming task to build a new frontend and am going to add in a couple days to try this out to see if it meets our needs.
We already went down this route several times since the first dotcom wave and all the frameworks that tried to target the browser as if we don't need to know "JavaScript, HTML and CSS".
Until we need to debug the application, or why it isn't rendering as it should.
It is also why I am not a big fan of Blazor, even though I admire its engineering effort.
There will always be essential complexity in dealing with the client/server nature of web apps. But there's still a lot of incidental complexity that can be burned off.
From my experience: besides both Win32 and VB being from the same entity (Microsoft), which helps a lot, what we had basically were VB bindings for the underlying Win32 library.
This Rio project seems more analogous to a library that tries to do an abstraction on top of Win32, like wxWidgets or Java's AWT. They work but the end results always seem a bit "off".
And unlike Win32, web technologies are moving targets and any assumptions one makes may be wrong some browser updates down the line... and there's where the nightmare comes
That is why Flash became so loved by Web designers, allowing them to target a rendering surface, completely bypassing the browser.
Also why we are now having Flash's revenge with WebGL/WebGPU/WebAssembly.
However the "until you have to debug it" still applies, unless you ship the browser with the application, but that isn't something people usually do. /s
It’s called HTML/CSS/JS.
Rio comes with its own set of debug tools, so I don't see debugging as a problem. Our components even explain their entire layouting flow, so I'd argue debugging Rio layout is much easer than CSS :P
For example, here's an excerpt of what the built-in dev-tools have to say about a button in one of my apps:
> The component was allocated a width of 104.0 by its parent MyRoot. Due to align_x being set, the Button only takes up the minimum amount of space necessary and is centered in the available space.
rio.Text(self.name, justify="left"),
Becomes: <span style="[...] text-align: left;">Dataset 1</span>
I'd prefer: rio.Span(self.name, text_align="left")Think of it like how Python has renamed a lot of things. What other languages call arrays, Python calls lists. HashTables are dicts, and so on. Python has faced a lot of resistance here from people that got used to the more technical names, but I think the popularity of the language speaks for itself. Easy to understand, meaningful names are a plus, not a downside :D
That is just false if you ask me. Eventually you reach the limits of the API defined by a framework and users will have to reach out to HTML and CSS. And now is there not only a level of indirection, but also all of the existing documentation from the Web Platform cannot be applied.
I think there is validity for having a Python based system (instead of JS) that runs on the client to render standard HTML and CSS, but this goes beyond that and will just become an immense scope creep.
Calling them arrays would be very confusing to everybody who expects a typical array: a pointer with some empty space after it.
The implementation defines the underlying data structure as PyObject *ob_item
When I said array, I specifically meant O(1) access, which is in contrast to linked lists, which the name "list" would seem to imply.
justify-content: center;
justify-content: start;
justify-content: end;
justify-content: flex-start;
justify-content: flex-end;
justify-content: left;
justify-content: right;Also, let's not pretend that html/css is particularly well designed or easy too learn. It's the backwards compatible result of decades of experimentation, where the initial design did not even remotely consider building interactive apps with it.
Modern web app dev requires learning way to much (archaic) stuff, just to create something that ought to be simple. Rio at least seems to be trying hard to address that.
That is what I read when I read the title. People should think about what a language's purpose is before planning to interate a technological design around it. Python is very good for many things just not this...
I agree with some of what you’re saying and it made me think of how common this is or not.
It appears this renders html using python syntax.
Just like any html avoidant libraries of JavaScript that need to be debugged.
React can have debugging too to output html.
Maybe less so but still the case for Rails for Ruby.
At least for me, there's some nostalgia involved. The longing of "simple" - at least for smaller apps / software. Being able to slap together some simple app in 15 minutes.
"We'll take your native constructs and jimmy them into some bastardized HTML" is almost always full of razor-sharp edge cases.
Apart from native a11y, hackability/"DX" and affordances like text selection, I feel that text rendering is a big moat of classic web technologies.
What a huge step back for the web.
Flexbox layout? CSS animations? Some custom npm library that I need to use to provide social logins, SDKs to integrate payment gateways? etc etc
If all you want is just a set of UI components, sure. We already have plenty of UI libraries out there.
These days there are many better ways to write low-JS, low-boilerplate code. HTMX for interactivity, UnoCSS for generated CSS on the fly. It's even possible not to bundle your ES6 modules these days, with <script type="importmap">.
While I have no idea how this would work, I think it would be more useful to have tools like this as a sort of template language for something like Django or Flask. So you get the mature frameworks on the backend and something like Rio to generate the backend, within the context of Django/Flask/Bottle/whatever.
Some modern web applications do need VueJS, React, something like that. CRUD apps mostly don't, but we are way past CRUD apps for a lot of thing. You can maybe get away with calling Asana and Jira CRUD apps, but you can't do Figma with just Django.
Local apps run inside of a webview. Think of it like electron but for Python. Even though this _should_ be cross platform, we've unfortunately found a lot of subtle issues with pywebview. That's why we're still considering this to be experimental.
In my experience webview works great on Windows, but struggles on Linux. For examples Videos don't play reliably when using the GTK backend.
We're looking into other ways to run a browser - my favorite would be to just find one already installed and just start it without UI - but that's some way off.
I am certain it does not need more Python.
Python is not perfect—no language is—but it arguably has the lowest barrier to entry for new programmers, with far fewer "wats" than languages of its kind and era (certainly less than JS). Sure, its reference implementation is not the most performant, but it easily interoperates with C/C++, and alternative implementations like PyPy are also relatively easy to switch to, so it can be performant when it needs to. Dynamic typing is not great for maintaining large codebases, but with the advent of gradual typing, this shouldn't be a major hindrance anymore. It has a great standard library, and a huge ecosystem. My only major gripe with it is the packaging and the insane amount of tooling around it, which I doubt will ever be resolved at this point. But Python is not so bad overall.
The thing is Python deserves all the hate JS gets and more.
1. The foot guns are real and mean (look up Mutable Default Arguments)
2. The language pushes beginners towards some bad habits (Deep inheritance) and away from good ones (Functional)
3. The performance is very poor (both single and multi threaded)
4. There are no real safe guards, and unexpected type behaviour
5. The packaging story is archaic with no fix in site. (There exist no standard out of the box way to guarantee deterministic builds)
Sure its good at Data, but that is a cultural accident, not by design.
Ecosystem is great - and probably the greatest thing Python has to offer after the aforementioned low barrier to entry. No language comes close if one wants to get up & going and try out AI/ML - whether using an API or using some packages to make models of one's own - it has everything one can ever need.
Built-in components do as much work as possible directly on the client. Any Python code however runs on the server. This makes it dead-simple to e.g. connect to your database and also gives you the full power of real CPython, not just a cut-down WASM/transpiled version.
Sure I love TypeScript, and use it every day, because it's the best solution to the current dumpster fire, but I'd like to get away from dumpsters some day. So it's really refreshing to see something good being done to replace this mess we call "Web Development"
Java and Applets pre-existed JavaScript, and purely due to a 10 day timing constraint put on him by Netscape management (right after their deal with Sun Microsystems), Brendan Eich, wanting a Java-syntax, but not having enough time to do it right, cobbled together JavaScript instead.
Stop spreading FUD. You have no idea what you’re talking about.
Stuff that people hate wasn’t even part of the original demo.
https://buttondown.com/hillelwayne/archive/did-brendan-eich-...
> Most of JavaScript's modern flaws are arguably not due to the short development time
Java applets could not interact with HTML at all, just render within a rectangle. They were in the plugin prison, where Flash shanked them nicely due to better tooling and innovation from Macromedia (bought by Adobe).
Any developer who has loved JS all their lives would've also loved Java if that's what was available to them all their life. It's largely just what you're used to.
Running JS on the server side is just a mess, and has only been popular to do since NodeJS was invented. Imagine if it was always the SAME code on both client and server starting since 1995. That would've definitely been a better world by far.
In addition to high-level components there's also some very basic building blocks, like a humble Rectangle. By combining these in clever ways you can get more styles than you might originally expect - just like everything on the web is ultimately colored boxes.
Just waiting for them to want their money out and then I am stuck deep in a product fast headed for enshitifaction or abandonment when it fails to make a billion dollars in 2 years.
It's desktop-first but compiles to WASM
It's honestly "just Rust", so I guess if you're looking for a DSL-type declarative, it doesn't quite fit the bill... but there are design reasons for why it's "just rust" and honestly I much prefer it. It still feels declarative enough
I am often in need of building internal tools, dashboards - simple apps with simple UI that doesn't need to be unique, drive engagement, or whatever. It needs to get the job done and let me move on.
Streamlit is close but the peculiar approach they take (rerun the script) makes it unwieldly for more complex apps (say, a few related pages, a few dozen components each).
I've been looking for a way to just let me do "GUI app in Python" that get delivered over HTTP and rendered in browser, and Rio is exactly what I was hoping for.
Yeah, no chance Meta will rewrite FB frontend to use Rio. Also pretty sure that I won't be doing any fancy websites in it. But if I can skip dealing with React/Vue/HTMX/whatever on the frontend for some internal thingy.
I only tried doing some simple stuff but so far I really like what I see!
just like there are new frameworks everyday in javascript
liveview kinda deal? python to js compiler? something else?
it drives me nuts when this isn’t in the readme, or from what i can find the docs
this is a major implementation detail that will determine the usecases for apps written in rio