<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: David</title>
    <description>The latest articles on DEV Community by David (@p4nd4no).</description>
    <link>https://dev.to/p4nd4no</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1504503%2F37532faa-1ddc-4e38-a846-dffcb0310ae1.jpg</url>
      <title>DEV Community: David</title>
      <link>https://dev.to/p4nd4no</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/p4nd4no"/>
    <language>en</language>
    <item>
      <title>Rio: Build Stunning GUIs and Full-Stack Web Apps in Pure Python — No HTML, CSS, or JS Needed!</title>
      <dc:creator>David</dc:creator>
      <pubDate>Sun, 02 Mar 2025 11:26:10 +0000</pubDate>
      <link>https://dev.to/p4nd4no/rio-build-stunning-guis-and-full-stack-web-apps-in-pure-python-no-html-css-or-js-needed-1fi6</link>
      <guid>https://dev.to/p4nd4no/rio-build-stunning-guis-and-full-stack-web-apps-in-pure-python-no-html-css-or-js-needed-1fi6</guid>
      <description>&lt;p&gt;What if you could build powerful, interactive web apps without ever touching HTML, CSS, or JavaScript? For Python developers, the dream of crafting sleek, modern user interfaces without stepping outside their favorite language has long been elusive. Most web frameworks demand an uncomfortable detour into frontend technologies. But Rio changes the game. &lt;a href="https://rio.dev/" rel="noopener noreferrer"&gt;https://rio.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rio is more than just another Python UI framework — it’s a complete reimagining of how Python developers build web apps. Inspired by React and Flutter, Rio brings declarative, component-based UI development directly into Python, completely eliminating the need to write or understand frontend code. You focus on Python, and Rio does the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forget the traditional backend/frontend divide. With Rio, your app is just Python — from logic to layout, from interactivity to deployment. And the best part? You can run the same codebase both locally and in the browser without modification.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This isn’t just a tool — it’s a revolution for Python developers who want to build simple GUIs or full-stack applications without leaving their comfort zone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnjlocbyb4gm5vsh1pl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnjlocbyb4gm5vsh1pl2.png" alt="Image description" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Rio?
&lt;/h2&gt;

&lt;p&gt;Rio addresses the challenges Python developers face when building modern web apps. Python is extremely simple and concise, making it one of the most popular programming languages in the world. Existing frameworks often require additional skills in HTML, CSS, or JavaScript, adding complexity and creating barriers for developers who prefer Python’s simplicity. Recognizing Python’s potential for streamlined and compact development, Rio envisioned a framework that allows users to focus entirely on Python without sacrificing functionality or flexibility.&lt;/p&gt;

&lt;p&gt;Rio eliminates the traditional divide between frontend and backend. Its automated communication simplifies development, removing the need for defining endpoints or sending requests manually. Inspired by the best aspects of frameworks like Flutter and React, Rio introduces a declarative interface, reusable components, and dynamic attribute binding to Python. These features enable developers to create powerful and maintainable applications with minimal effort.&lt;/p&gt;

&lt;p&gt;Many projects rely on popular libraries like React internally, but the core benefits and elegance of these libraries are often diluted in the process. Take React, for example — its defining feature is that the “app is code,” where components are dynamically built within a render method that automatically re-triggers upon state changes. However, this fundamental principle is lost in libraries that simply wrap React. It contradicts the very premise of React and the reasons for its widespread popularity among developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rio’s Scalability:
&lt;/h2&gt;

&lt;p&gt;🔹Modern and clear project structure&lt;/p&gt;

&lt;p&gt;🔹Reusable components&lt;/p&gt;

&lt;p&gt;🔹Suitable for everything from POCs to production projects&lt;/p&gt;

&lt;p&gt;🔹Versatile for hobbyists and B2B users alike&lt;/p&gt;

&lt;p&gt;🔹Unlimited GUI designs with fully customizable components&lt;/p&gt;

&lt;h2&gt;
  
  
  Modern Developer Experience
&lt;/h2&gt;

&lt;p&gt;🔹Hot Reloading for seamless development&lt;/p&gt;

&lt;p&gt;🔹Static typing with extensive IDE support&lt;/p&gt;

&lt;p&gt;🔹Classic Python debugging&lt;/p&gt;

&lt;p&gt;🔹Targeted error messages in both the console and GUI&lt;/p&gt;

&lt;p&gt;🔹Custom layout system enabling Python-only syntax&lt;/p&gt;

&lt;p&gt;🔹Modern dev tools like Component Tree and Theme Picker&lt;/p&gt;

&lt;p&gt;Rio makes UI development as natural as writing a script. Developers no longer need to wrestle with unfamiliar paradigms — just use Python the way you always have, and let Rio handle the complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Your First Rio App in 30 Seconds ⏱️
&lt;/h2&gt;

&lt;p&gt;Getting started with Rio is lightning-fast. First install the rio library using pip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install rio-ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rio comes with a very helpful command line utility to help you out. It establishes the project structure, theme, app, and related components. Create a new project in one short command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rio new
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can choose from a variety of built-in templates to get you started. Here’s a complete example to create a project based on the tic-tac-toe template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rio new my-project --type website --template "Tic-Tac-Toe"
cd my-project
rio run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your first web app is up and running. No frontend headaches, no complex setup — just Python.&lt;/p&gt;

&lt;p&gt;Check out more examples: &lt;a href="https://rio.dev/examples" rel="noopener noreferrer"&gt;https://rio.dev/examples&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click, explore, and experience how they look and behave right from the landing page. No more guessing — just dive in and see Rio in action!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv8wa3bozcst0a9m9r6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzv8wa3bozcst0a9m9r6z.png" alt="Image description" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple Counter App
&lt;/h2&gt;

&lt;p&gt;Here’s a minimal yet powerful example that showcases Rio’s declarative, component-based design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Define a component that counts button clicks
class ButtonClicker(rio.Component):
    # Define the attributes of the component. Rio will watch these
    # for changes and automatically update the GUI.
    clicks: int = 0

    # Define a method that increments the click count. We'll later
    # make a button that calls this method whenever it is pressed.
    def _on_press(self) -&amp;gt; None:
        self.clicks += 1

    # Define the `build` method. This method essentially tells rio
    # what a ButtonClicker component looks like. Whenever the state
    # of the ButtonClicker component changes, rio will call its
    # `build` method and update the GUI according to the output.
    def build(self) -&amp;gt; rio.Component:
        return rio.Column(
            rio.Button('Click me', on_press=self._on_press),
            rio.Text(f'You clicked the button {self.clicks} time(s)'),
        )

# Create an App and tell it to display a ButtonClicker when it starts
app = rio.App(build=ButtonClicker)
app.run_in_browser()  # Or `app.run_in_window()` to run as local app!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rio automatically handles the UI rendering, state management, and updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Rio Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqujavbvjkvvwp1gz7nh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqujavbvjkvvwp1gz7nh.png" alt="Image description" width="800" height="781"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user code is written entirely in Python and is responsible for defining the UI components of the app or website. From this point, Rio takes over: the components are automatically converted into HTML, CSS, and JavaScript, which are sent to the user’s browser.&lt;/p&gt;

&lt;p&gt;A WebSocket connection keeps the server and client in sync. When a user interacts with the website, a message is automatically sent to the server, and UI updates are synchronized with the client. This process requires no intervention from the developer — there’s no need to manually define endpoints or send HTTPS requests.&lt;/p&gt;

&lt;p&gt;On the client side, Rio’s layout system manages the positioning of components on the screen and dynamically adjusts the website’s DOM based on the server’s instructions.&lt;/p&gt;

&lt;p&gt;Rio components are the building blocks of your web app. They are the visual elements that the user interacts with. You can use them to create buttons, text inputs, images, and more. Each component has its own set of properties that you can customize to fit your needs.&lt;/p&gt;

&lt;p&gt;To learn more about Rios components, head over to &lt;a href="https://rio.dev/docs/api" rel="noopener noreferrer"&gt;https://rio.dev/docs/api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ressources:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Documentation: &lt;a href="https://rio.dev/docs" rel="noopener noreferrer"&gt;https://rio.dev/docs&lt;/a&gt;&lt;br&gt;
Website: &lt;a href="https://rio.dev/" rel="noopener noreferrer"&gt;https://rio.dev/&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/rio-labs/rio" rel="noopener noreferrer"&gt;https://github.com/rio-labs/rio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>opensource</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Rio: WebApps in pure Python — A fresh Layouting System</title>
      <dc:creator>David</dc:creator>
      <pubDate>Sun, 03 Nov 2024 10:25:35 +0000</pubDate>
      <link>https://dev.to/p4nd4no/rio-webapps-in-pure-python-a-fresh-layouting-system-23p3</link>
      <guid>https://dev.to/p4nd4no/rio-webapps-in-pure-python-a-fresh-layouting-system-23p3</guid>
      <description>&lt;p&gt;We recently launched Rio, our new framework designed to help you create web and local applications using just pure Python. The response from our community has been overwhelmingly positive and incredibly motivating for us. With the praise has come a wave of curiosity. The most common question we’ve encountered is, “How does Rio actually work?” If you’ve been wondering the same thing, you’re in the right place! Here we’ll explore the inner workings of Rio and uncover what makes it so powerful.&lt;/p&gt;

&lt;h1&gt;
  
  
  A Fresh Layouting System
&lt;/h1&gt;

&lt;p&gt;When it comes to building modern apps, components are just the beginning, it’s the layouting that pulls them together into a cohesive, user-friendly interface. In our last topic, we took a closer look at components, the essential pieces of any app. Now, let’s shift our focus to the layout system that arranges them harmoniously. Designing a layout system isn’t a one-size-fits-all task; different frameworks bring unique strengths, with CSS often at the center of debate. As we designed Rio's layout system, we aimed for something Pythonic, simple, flexible, and efficient—a system that keeps developers focused on their app’s function, not the complexities of positioning. Here, we’ll break down the core principles behind Rio’s two-step approach to layouting, where each component starts by defining its own natural size before the available space is thoughtfully distributed.&lt;/p&gt;

&lt;p&gt;Take a look at our playground, where you can try out our layout concept firsthand with just a click and receive real-time feedback.&lt;br&gt;
&lt;a href="https://rio.dev/docs/howto/layout-guide" rel="noopener noreferrer"&gt;Layouting Quickstart&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What Makes a Great Layout System
&lt;/h1&gt;

&lt;p&gt;Each UI framework approaches layouting differently, all with their own unique strengths and quirks. There's of course the &lt;em&gt;polarizing incumbent&lt;/em&gt;, CSS, but also the many systems built into popular frameworks like Flutter, QT, and others. Before we got to designing our own, we took a step back to understand what makes a great layout system. Here are some key principles we identified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pythonic:&lt;/strong&gt; Rio embraces Python’s simplicity. No numbers encoded as strings&lt;br&gt;
or complex unit declarations. For example, &lt;code&gt;width=10&lt;/code&gt; is preferred over&lt;br&gt;
&lt;code&gt;width="10px"&lt;/code&gt;. This isn’t just cleaner, but also aids type checking tools and&lt;br&gt;
allows for easy mathematical operations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simple:&lt;/strong&gt; The system should be intuitive, even for developers without a deep&lt;br&gt;
background in UI design. Rather than a tangled set of rules and exceptions, it&lt;br&gt;
should be governed by a handful of principles that are applied consistently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexible:&lt;/strong&gt; From basic layouts to complex, nested structures, the system&lt;br&gt;
needs to handle them all. Templates and restrictive built-in patterns won’t&lt;br&gt;
cut it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficient:&lt;/strong&gt; Especially when targeting the web, performance is key. A good&lt;br&gt;
layouting system should be automatically convertible to CSS, maybe with some&lt;br&gt;
JavaScript sprinkled in occasionally for dynamic calculations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Rio’s Approach: Two-Step Layouting
&lt;/h1&gt;

&lt;p&gt;We've decided on a two-step layouting system that balances simplicity and&lt;br&gt;
flexibility. Here's how it works:&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Natural Size Calculation
&lt;/h2&gt;

&lt;p&gt;First, each component determines how much space it needs to fit its content. We&lt;br&gt;
call this the component's "natural size."&lt;/p&gt;

&lt;p&gt;For some components this is simple. For example, &lt;code&gt;rio.Switch&lt;/code&gt; has a fixed size,&lt;br&gt;
so that is also its natural size. But not all components are that simple. Take a&lt;br&gt;
&lt;code&gt;rio.Row&lt;/code&gt; for example. The row itself doesn't need any space, but it needs to&lt;br&gt;
request enough space to fit its children. So the natural width of a row is the&lt;br&gt;
sum of the natural widths of its children, plus any spacing between them.&lt;/p&gt;

&lt;p&gt;Another more in-depth example is &lt;code&gt;rio.Text&lt;/code&gt;. It's size depends on a variety of&lt;br&gt;
things, such as its text content, font size, whether the font is bold, etc.&lt;/p&gt;

&lt;p&gt;This process starts at the leaves of the component tree, i.e. first components&lt;br&gt;
without any children are calculated, then their parents, and so on, until the&lt;br&gt;
entire tree has computed its natural width &amp;amp; height.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Space Distribution
&lt;/h2&gt;

&lt;p&gt;Once each component has determined its natural size, we must decide how to&lt;br&gt;
allocate the available space. For example, in a large window with only a button,&lt;br&gt;
should the button be centered, aligned to one side, or stretched?&lt;/p&gt;

&lt;p&gt;There isn't a real reason to prefer one over the other. We are solving this, by&lt;br&gt;
simply giving &lt;em&gt;all&lt;/em&gt; space to the button. If you don't want for that to happen,&lt;br&gt;
you can explicitly set the button's alignment, and Rio will take it into account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Imagine a simple &lt;code&gt;rio.Row&lt;/code&gt; containing a &lt;code&gt;rio.Text&lt;/code&gt; and a &lt;code&gt;rio.Switch&lt;/code&gt;. First, we&lt;br&gt;
need to calculate the natural size of all components. We'll start with&lt;br&gt;
components that don't have any children, so in this case the &lt;code&gt;rio.Text&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;rio.Switch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rio.Text&lt;/code&gt; will calculate its natural size based on its text content, font&lt;br&gt;
size, etc. The &lt;code&gt;rio.Switch&lt;/code&gt; has a fixed size, so that is also its natural size.&lt;/p&gt;

&lt;p&gt;Now that all children have had their natural size calculated, the &lt;code&gt;rio.Row&lt;/code&gt; can&lt;br&gt;
get to work. It's natural width is the sum of the natural widths of its children&lt;br&gt;
(plus any spacing) and its natural height is the maximum of the natural heights&lt;br&gt;
of its children.&lt;/p&gt;

&lt;p&gt;Finally, we need to distribute the available space. Since the window itself&lt;br&gt;
always has a single child, it will pass all available space to that child - in&lt;br&gt;
this case the &lt;code&gt;rio.Row&lt;/code&gt;. The row will then distribute the space to its children;&lt;br&gt;
But how?&lt;/p&gt;

&lt;p&gt;Since there's only so few components in the view there is likely too much space&lt;br&gt;
available. Thus, the &lt;code&gt;rio.Row&lt;/code&gt; will have to decide how much space to pass to&lt;br&gt;
each child. Since we always want all components to have enough space to fit&lt;br&gt;
their content ("natural size") we'll allocate each child that much space. Then,&lt;br&gt;
if space is leftover we can distribute that proportionally. Ta-da! All&lt;br&gt;
components now know how large they are. Their positions also follow from this.&lt;/p&gt;

&lt;p&gt;Since this is such a common use-case, &lt;code&gt;rio.Row&lt;/code&gt; also honors the &lt;code&gt;grow_x&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;grow_y&lt;/code&gt; attributes of components. If a component is marked to &lt;em&gt;grow&lt;/em&gt;, and&lt;br&gt;
superfluous space is available, all space will be given to that component. If&lt;br&gt;
there are multiple components that are marked to grow, the space will be&lt;br&gt;
distributed proportionally just between those components.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementation
&lt;/h1&gt;

&lt;p&gt;The system described above is what we call our reference layouting system. It&lt;br&gt;
isn't actually implemented like this in code, but rather as a set of CSS rules,&lt;br&gt;
that result in this exact behavior. This allows our layouting to run at maximum&lt;br&gt;
performance, because it relies on the browser's native layouting engine. The&lt;br&gt;
described algorithm is nonetheless useful, as it guides Rio developers to how&lt;br&gt;
a component should behave. It's just that this behavior is then achieved by&lt;br&gt;
internal CSS rules rather than the algorithm itself.&lt;/p&gt;

&lt;p&gt;Best of all, you'll never have to see a single line of CSS. All of this is&lt;br&gt;
handled by Rio internally, so you can focus on building your app.&lt;/p&gt;

&lt;h1&gt;
  
  
  Limitations and Trade-offs
&lt;/h1&gt;

&lt;p&gt;While Rio’s layout system is powerful and flexible, it isn't perfect. In the&lt;br&gt;
interest of full transparency, we'd like to share some limitations that we've&lt;br&gt;
found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Some layouts cannot achieved just using CSS. Notably, when using the&lt;br&gt;
&lt;code&gt;proportions&lt;/code&gt; attribute of &lt;code&gt;rio.Row&lt;/code&gt; or &lt;code&gt;rio.Column&lt;/code&gt;, JavaScript jumps into&lt;br&gt;
action to help out, because we are not aware of any pure-CSS way to achieve&lt;br&gt;
our desired behavior. (If you're a CSS magician and know a way, reach out!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are occasional layouts that cannot be realized with this system. One&lt;br&gt;
such situation that we've found is to have a row containing an icon and text,&lt;br&gt;
while that text is both centered and has wrapping enabled.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This sounds like a simple case, but no combination of parameters yields the&lt;br&gt;
  desired result. Aligning the text to &lt;code&gt;0.5&lt;/code&gt; (center) won't center the icon.&lt;br&gt;
  Same when using the &lt;code&gt;justify&lt;/code&gt; attribute. Aligning the entire &lt;code&gt;rio.Row&lt;/code&gt; will&lt;br&gt;
  make the row take up as little space as possible, thus squishing the text.&lt;/p&gt;

&lt;p&gt;We've had some discussions about introducing a "preferred size" that would&lt;br&gt;
  solve this, but it's not in Rio yet.&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/rio-labs/rio" rel="noopener noreferrer"&gt;https://github.com/rio-labs/rio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://rio.dev/" rel="noopener noreferrer"&gt;https://rio.dev/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rio: WebApps in pure Python — Technical Description</title>
      <dc:creator>David</dc:creator>
      <pubDate>Sun, 04 Aug 2024 11:12:44 +0000</pubDate>
      <link>https://dev.to/p4nd4no/rio-webapps-in-pure-python-technical-description-60</link>
      <guid>https://dev.to/p4nd4no/rio-webapps-in-pure-python-technical-description-60</guid>
      <description>&lt;p&gt;We  recently launched Rio (&lt;a href="https://github.com/rio-labs/rio" rel="noopener noreferrer"&gt;https://github.com/rio-labs/rio&lt;/a&gt;), our new framework designed to help you create  web and local applications using just pure Python. The response from our  community has been overwhelmingly positive and incredibly motivating  for us.&lt;/p&gt;

&lt;p&gt;With the praise has come a wave of curiosity. The most common question we’ve encountered is, &lt;strong&gt;“How does Rio actually work?”&lt;/strong&gt;  If you’ve been wondering the same thing, you’re in the right place!  Here we’ll explore the inner workings of Rio and uncover what makes it  so powerful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We will explore the following topics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What are Components?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How does observing Attributes work?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How does Diffing and Reconciliation work?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Components are Dataclasses
&lt;/h2&gt;

&lt;p&gt;Among the numerous classes and functions in Rio, one stands out as indispensable: &lt;code&gt;rio.Component&lt;/code&gt;. This base class is omnipresent throughout the code, forming the foundation for every component in an app, including both user-defined and built-in components.&lt;/p&gt;

&lt;p&gt;Components in Rio have several key responsibilities. Primarily, they manage the state of your app. For instance, when a user enters text into a &lt;code&gt;rio.TextInput&lt;/code&gt;, you'll need to store that value. Simply asking for user input without saving it won't make for a satisfying user experience. :)&lt;/p&gt;

&lt;p&gt;To streamline value storage, all Rio components are designed to automatically function as &lt;code&gt;dataclass&lt;/code&gt;es. Dataclasses in Python help reduce boilerplate code for many simple classes. For example, if you need to store information about a customer, without using dataclasses, your code might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Cat:
    def __init__(self, name: str, age: int, loves_catnip: bool) -&amp;gt; None:
        self.name = name
        self.age = age
        self.loves_catnip = loves_catnip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is functional but quite verbose. Notice how each attribute name must be repeated three times: once as the function parameter, once as the class attribute, and once to assign the parameter value to the attribute. The redundancy becomes even more cumbersome when inheritance is introduced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Animal:
    def __init__(self, name: str, age: int) -&amp;gt; None:
        self.name = name
        self.age = age


class Cat(Animal):
    def __init__(self, name: str, age: int, loves_catnip: bool) -&amp;gt; None:
        super().__init__(name, age)
        self.loves_catnip = loves_catnip


class Dog(Animal):
    def __init__(self, name: str, age: int, is_good_boy: bool) -&amp;gt; None:
        super().__init__(name, age)
        self.is_good_boy = is_good_boy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how often we had to write same the attribute names. This repetition is so common that the developers of Python introduced dataclasses as a simpler alternative. Here's how the same scenario looks using dataclasses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from dataclasses import dataclass


@dataclass
class Animal:
    name: str
    age: int


@dataclass
class Cat(Animal):
    loves_catnip: bool


@dataclass
class Dog(Animal):
    is_good_boy: bool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is much simpler and requires significantly less effort while achieving the same result. Additionally, dataclasses offer extra benefits, such as an automatic comparison function (amongst others), allowing us to easily check if two instances are identical.&lt;/p&gt;

&lt;p&gt;Since Rio components need to store values and all inherit from &lt;code&gt;rio.Component&lt;/code&gt;, it made perfect sense to make them all dataclasses. This is why Rio components always come with the same, familiar structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CatInput(rio.Component):
    name: str
    age: int
    loves_catnip: bool

    def build(self) -&amp;gt; rio.Component:
        return ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure should look familiar: attributes are defined at the top, there's no &lt;code&gt;__init__&lt;/code&gt; function, and a &lt;code&gt;build&lt;/code&gt; method is used to create the component's user interface. Whenever any of the attributes change, build is called again, updating the component accordingly.&lt;/p&gt;

&lt;p&gt;This raises the question: how does Rio detect when a component changes?&lt;/p&gt;

&lt;h2&gt;
  
  
  Observing Attributes (aka, I feel watched!)
&lt;/h2&gt;

&lt;p&gt;As we've just seen, one of the reasons Rio components are dataclasses is convenience. Notice how in the &lt;code&gt;dataclass&lt;/code&gt; version of &lt;code&gt;Animal&lt;/code&gt;, we are explicitly informing Python which fields the class has, and their types. For example, we're writing &lt;code&gt;name: str&lt;/code&gt;. Because of this, Python knows exactly that each animal will have a field named &lt;code&gt;name&lt;/code&gt;, and that the value of that field will always be a string.&lt;/p&gt;

&lt;p&gt;Compare that to the regular class. We're telling Python that the &lt;code&gt;__init__&lt;/code&gt; function accepts a parameter called &lt;code&gt;name&lt;/code&gt;, and we copy that value into the class, but we never tell Python about it. The interpreter has no clue which fields the class comes with, and what their datatypes are.&lt;/p&gt;

&lt;p&gt;Explicit fields are not only a good idea, because they help out other developers reading your code, but because libraries such as Rio can read them as well. Because we have explicitly listed our fields, Rio now knows which values the class has, and will watch those for changes for us. How? Simple, using &lt;code&gt;__setattr__&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Python classes can have magic methods. You've seen these before, they're methods starting &amp;amp; ending with two underscores. &lt;code&gt;__init__&lt;/code&gt; is one of those methods.&lt;/p&gt;

&lt;p&gt;Another method is &lt;code&gt;__setattr__&lt;/code&gt;. Python calls this function each time you assign a value to a class's attribute. You can use this to store values in a JSON value, whenever they're assigned to. Or maybe you're debugging code and want to &lt;code&gt;print&lt;/code&gt; new values when they change. Or, of course, maybe you want to be informed whenever an attribute changes, so you can rebuild the UI. This is exactly what Rio does.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyClass:
    def __setattr__(self, name, value):
        print(f"Setting {name} to {value}")
        self.__dict__[name] = value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why it's crucial to always assign a new value to a component's attribute when you change it. If you modify an attribute without assignment (for example, by appending to a list), Python won't trigger &lt;code&gt;__setattr__&lt;/code&gt;, and Rio won't know that your component needs to be updated. If your component seems unresponsive, check your code to ensure you are assigning a new values to the attributes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diffing &amp;amp; Reconciliation
&lt;/h2&gt;

&lt;p&gt;So, Rio has detected that your component has changed, &lt;code&gt;build&lt;/code&gt; has been called, and a new set of components has been created. What happens next? Should Rio simply discard the old components and replace them with the new ones? No! The previous components may contain a lot of important state that needs to be preserved. Imagine this scenario: a user has entered the perfect cat name into your app, toggled some switches, and selected an item from a dropdown menu. Then, they trigger an event, perhaps by pressing a button or resizing the window. Your event handler is called and updates a component. If Rio were to replace the old components with the new ones, that precious cat name would be lost forever.&lt;/p&gt;

&lt;p&gt;Instead, Rio uses a set of techniques called &lt;strong&gt;diffing &amp;amp; reconciliation&lt;/strong&gt;. The first step is to find matches between the old and new components. For instance, if the &lt;code&gt;build&lt;/code&gt; function previously returned a &lt;code&gt;TextInput&lt;/code&gt; and returns a &lt;code&gt;TextInput&lt;/code&gt; again, it's likely the same component with updated state. This process of finding matching pairs is known as diffing. The basic idea is simple: Rio recursively walks the new and old output of the build function. If it encounters two components of the same type, they are considered a match. Rio then continues the search into the component's children, looking for matches there as well. If two components do not match, the recursive search stops, and the component is considered new. This "structural" matching works well in most cases and identifies most matches.&lt;/p&gt;

&lt;p&gt;However, there are situations where it isn't sufficient. For example, imagine a list of many components. Depending on the user's actions, new components may be added or removed, changing the order of existing entries. If we were to simply match the first component in the old list with the first in the new list, we'd quickly encounter problems. To avoid this, Rio uses a second technique based on explicit keys. You might have noticed a &lt;code&gt;key&lt;/code&gt; parameter in a Rio component before. This optional parameter is common to all components, and some even require you to set one.&lt;/p&gt;

&lt;p&gt;If a component in the &lt;code&gt;build&lt;/code&gt; output has the same key as a component in the previous output, they are always considered a match, regardless of changes in their parent or overall position. This allows Rio to track components that have moved and update them accordingly.&lt;/p&gt;

&lt;p&gt;Now, with matching pairs of components identified, the reconciliation step begins. Rio compares the paired components and determines which attributes to retain from each version:&lt;/p&gt;

&lt;p&gt;Attributes which you have explicitly set on the new component always take priority&lt;/p&gt;

&lt;p&gt;Attributes which have changed on the previous component after their initialization are retained&lt;/p&gt;

&lt;p&gt;Finally, any other attributes are taken from the new component&lt;/p&gt;

&lt;p&gt;These rules strike a good balance, always honoring new values while preserving the previous state if it was likely intentionally set.&lt;/p&gt;

&lt;p&gt;This concludes the first installment of our deep dive series. The next part will be available in the coming weeks. In the meantime, join our Discord server! You can showcase the cool apps you've built or get help if you're still early in your journey.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/rio-labs/rio" rel="noopener noreferrer"&gt;https://github.com/rio-labs/rio&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
