DEV Community

Cover image for WebForms.py 2.1 Released — Bringing WebForms Core to Python
Elanat Framework
Elanat Framework

Posted on

WebForms.py 2.1 Released — Bringing WebForms Core to Python

WebForms.py 2.1 is now available, bringing the WebForms Core programming model to Python web applications through a Python implementation of the WebForms Commander.

WebForms Core is based on a simple separation between two components:

The server creates commands, while the client executes them. This approach allows developers to modify the web page from the server without having to manually write JavaScript for every UI operation.

WebForms Core: Commander and Executor

WebForms Core separates the responsibility of generating UI operations from executing those operations.

WebFormsJS works as the Executor. It runs in the browser and receives the commands generated by the server. The JavaScript library is responsible for finding the requested HTML elements and applying the requested operations to them.

The WebForms class in WebForms.py works as the Commander.

Instead of directly manipulating the DOM from Python, the developer creates commands through the WebForms class.

For example:

form = WebForms()

form.set_text(
    InputPlace.id('result'),
    'Hello from Python!'
)

return form.response()
Enter fullscreen mode Exit fullscreen mode

Here, Python does not directly access the browser DOM.

The WebForms object describes what should happen:

Find the element with the result ID and change its text.

The resulting response is then processed by WebFormsJS in the browser.

This creates a clear separation:

Python / Server
      │
      │ WebForms
      │ Commander
      ▼
 WebForms Response
      │
      ▼
 WebFormsJS
 Executor
      │
      ▼
 Browser DOM
Enter fullscreen mode Exit fullscreen mode

This model is particularly useful for server-side applications where the developer wants to keep the UI logic close to the server-side code.

WebForms.py 2.1

Version 2.1 updates the Python implementation of the WebForms Core Commander.

The WebForms class provides methods for creating operations that are eventually executed by WebFormsJS.

One important part of the API is InputPlace.

InputPlace provides a way to describe where an operation should be performed.

For example:

InputPlace.id('result')
Enter fullscreen mode Exit fullscreen mode

means that the operation should target the HTML element whose ID is result.

This allows WebForms commands to target elements without requiring the developer to manually write JavaScript selectors.

Setting Text

One of the simplest operations is changing the text of an element.

In the example application, the result is displayed using:

form.set_text(
    InputPlace.id('result'),
    result
)
Enter fullscreen mode Exit fullscreen mode

The important part here is not the Python string itself, but the WebForms command.

The developer specifies:

  1. Where the operation should happen — InputPlace.id('result')
  2. What should happen — set_text()
  3. What value should be used — result

WebFormsJS then executes this command in the browser.

The same approach is used for the result description:

form.set_text(
    InputPlace.id('result-detail'),
    result_detail
)
Enter fullscreen mode Exit fullscreen mode

And for displaying the number generated by the server:

form.set_text(
    InputPlace.id('computer'),
    server_number_text
)
Enter fullscreen mode Exit fullscreen mode

This means the Python application can update several parts of the existing page without returning a new HTML document.

Increasing a Value

WebForms.py also allows numerical values displayed in the page to be modified through commands.

The example uses:

form.increase(InputPlace.id('counter'), 1)
Enter fullscreen mode Exit fullscreen mode

This tells WebFormsJS to increase the numerical value displayed in the counter element by 1.

The same method is used for the player's income:

form.increase(
    InputPlace.id('win-counter'),
    100
)
Enter fullscreen mode Exit fullscreen mode

Depending on the game result, the server sends a different command:

form.increase(InputPlace.id('win-counter'), 100)
Enter fullscreen mode Exit fullscreen mode

or:

form.increase(InputPlace.id('win-counter'), 5)
Enter fullscreen mode Exit fullscreen mode

or:

form.increase(InputPlace.id('win-counter'), 1)
Enter fullscreen mode Exit fullscreen mode

Again, the Python code is only creating the command. WebFormsJS is responsible for executing it on the client.

Returning the WebForms Response

After the commands have been created, the application returns:

return form.response()
Enter fullscreen mode Exit fullscreen mode

This is the point where the Commander produces the response that can be handled by WebFormsJS.

Therefore, the basic pattern is:

form = WebForms()

form.set_text(
    InputPlace.id('result'),
    'Hello!'
)

form.increase(
    InputPlace.id('counter'),
    1
)

return form.response()
Enter fullscreen mode Exit fullscreen mode

The server does not need to generate JavaScript code for these operations.

It creates a WebForms response, and WebFormsJS executes that response in the browser.

Example: Number Guess

The following example uses Flask as the web server and WebForms.py for server-side UI commands.

The game itself generates three random numbers on the server and compares them with the numbers entered by the player.

The important part from the WebForms perspective is what happens after the server has calculated the result.

When the input is invalid, a WebForms command is created:

form = WebForms()

form.set_text(
    InputPlace.id('result'),
    '⚠️ Please enter numbers between 0 and 9.'
)

return form.response()
Enter fullscreen mode Exit fullscreen mode

When the game has a valid result, several commands are created:

form = WebForms()

form.increase(InputPlace.id('counter'), 1)

form.set_text(
    InputPlace.id('computer'),
    server_number_text
)

form.set_text(
    InputPlace.id('result'),
    result
)

form.set_text(
    InputPlace.id('result-detail'),
    result_detail
)

return form.response()
Enter fullscreen mode Exit fullscreen mode

The complete application demonstrates how a Python server can calculate the result and then use WebForms.py to update multiple elements in the existing page.

Full Code

from flask import Flask, request, render_template_string
from WebForms import WebForms, InputPlace
import random

app = Flask(__name__)


@app.route('/', methods=['GET', 'POST'])
def index():

    if request.method == 'POST' and 'btn_Play' in request.form:

        # Get player's three numbers
        number1 = request.form.get('txt_Number1', '')
        number2 = request.form.get('txt_Number2', '')
        number3 = request.form.get('txt_Number3', '')

        # Validate input
        try:
            player_numbers = [
                int(number1),
                int(number2),
                int(number3)
            ]

            if any(number < 0 or number > 9 for number in player_numbers):
                raise ValueError

        except (ValueError, TypeError):

            form = WebForms()
            form.set_text(
                InputPlace.id('result'),
                '⚠️ Please enter numbers between 0 and 9.'
            )

            return form.response()

        # Generate three random digits on the server
        server_numbers = [
            random.randint(0, 9),
            random.randint(0, 9),
            random.randint(0, 9)
        ]

        # Compare each position
        correct_count = sum(
            player_numbers[i] == server_numbers[i]
            for i in range(3)
        )

        # Create WebForms response
        form = WebForms()

        # Result
        if correct_count == 3:
            result = '🏆 Amazing! 100$'
            result_detail = 'All three numbers are correct! Do not mistake luck for skill.'
            form.increase(InputPlace.id('win-counter'), 100)
        elif correct_count == 2:
            result = '🌟 Very Nice! 5$'
            result_detail = 'Two numbers are correct! Randomness is giving you confidence.'
            form.increase(InputPlace.id('win-counter'), 5)
        elif correct_count == 1:
            result = '👍 Good! 1$'
            result_detail = 'One number is correct! There is no strategy here.'
            form.increase(InputPlace.id('win-counter'), 1)
        else:
            result = '😢 Try Again!'
            result_detail = 'None of the numbers are correct. That urge to try again is exactly how gambling traps people.'

        # Increase game counter
        form.increase(InputPlace.id('counter'), 1)

        # Show server number
        server_number_text = (
            f'{server_numbers[0]}'
            f'{server_numbers[1]}'
            f'{server_numbers[2]}'
        )

        form.set_text(
            InputPlace.id('computer'),
            server_number_text
        )

        # Show result
        form.set_text(InputPlace.id('result'), result)

        # Show result details
        form.set_text(
            InputPlace.id('result-detail'),
            result_detail
        )

        return form.response()

    return render_template_string('''
    <!DOCTYPE html>
    <html>

    <head>
        <title>Number Guess - WebForms Core</title>

        <script type="module"
                src="/static/script/web-forms.js">
        </script>
        <style>
        input{
        width: 50px;
        height: 50px;
        font-size: 20px;}
        </style>
    </head>

    <body>

        <h1>🎯 Number Guess</h1>
        <p>Chances: 3 correct = 0.1%, 2 correct = 2.7%, 1 correct = 24.3%</p>
        <p>Choose three numbers between 0 and 9:</p>

        <form method="post" action="/">

            <input
                name="txt_Number1"
                id="txt_Number1"
                type="number"
                value="0"
                min="0"
                max="9"
                required
            />

            <input
                name="txt_Number2"
                id="txt_Number2"
                type="number"
                value="0"
                min="0"
                max="9"
                required
            />

            <input
                name="txt_Number3"
                id="txt_Number3"
                type="number"
                value="0"
                min="0"
                max="9"
                required
            />

            <br><br>

            <input
                name="btn_Play"
                id="btn_Play"
                type="submit"
                value="Play"
            />

        </form>

        <hr>

        <p>
            Server number: <b id="computer">???</b>
        </p>

        <h2 id="result"></h2>

        <p id="result-detail"></p>

        <p>
            Games:
            <span id="counter">0</span>$
        </p>

        <p>
            Income:
            <span id="win-counter">0</span>$
        </p>

    </body>
    </html>
    ''')


if __name__ == '__main__':
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

Screenshot

Running Number Guess example using WebForms.py 2.1

More Than Simple DOM Updates

Please note that these examples are intentionally simple and introductory. The WebForms class provides a large number of powerful methods for building much more advanced interactions and applications.

The WebForms class is not limited to simple operations such as changing text or increasing a value. Its API contains a wide range of methods for DOM manipulation, event handling, state management, networking, WebAssembly, WebSocket, Server-Sent Events, conditional execution, format storage, caching, and more.

The following are just 20 examples from the extensive API available in the WebForms class:

Method Description
SetAttribute Sets or updates an HTML attribute on the target element.
Delete Removes the target element from the DOM.
SwapTag Replaces an element's HTML tag while preserving its relevant content.
SetReflection Creates a reflection between elements, allowing values or changes to be synchronized.
SetMorph Applies a morph operation to modify an element while maintaining the required DOM structure.
TriggerEvent Triggers an HTML event on the target element.
SetPostEvent Configures a POST event that can communicate with the server.
SetWebSocketEvent Configures an event that communicates through WebSocket.
SetSSEEvent Configures an event or interaction using Server-Sent Events (SSE).
LoadModule Loads a WebForms module dynamically on the client.
SaveState Saves application or UI state for later use.
LoadState Loads previously saved state and makes it available to the application.
SetCookie Creates or updates a browser cookie through a WebForms command.
CallMethod Calls a JavaScript method from a server-generated WebForms command.
CallWasmBack Calls back into a WebAssembly-related operation.
Increase Increases a numerical value on the target element.
StartTransientDOM Starts a Transient DOM operation for controlled temporary DOM processing.
Alert Displays a browser alert message.
ForEach Applies a sequence of WebForms operations to multiple elements.
CreateFormatStorage Creates a format storage that can work with structured data such as JSON, XML, INI, or text.

These methods represent only a small selection of the functionality available in the WebForms class. The API also includes methods for REST-style events, WebSocket connections, SSE connections, WebAssembly, service workers, caching, browser state, conditional logic, loops, asynchronous execution, format stores, module management, debugging, and client-side JavaScript interaction.

Using WebForms Core in Python

This extensive API allows WebForms.py to go beyond simple server-side HTML updates and act as a complete Commander for the WebForms Core architecture.

The developer can construct complex client-side behavior from the server while WebFormsJS remains responsible for executing those commands in the browser.

Why the Commander–Executor Model Matters

A major characteristic of WebForms Core is that the server and browser have different responsibilities.

The Python application does not need to know how the browser will manipulate the DOM.

It only creates the required commands:

form.set_text(...)
form.increase(...)
Enter fullscreen mode Exit fullscreen mode

WebFormsJS receives and executes those commands.

This makes the Python code focused on the application's server-side logic while the client-side library handles DOM execution.

In other words:

WebForms.py
    │
    │ Creates commands
    ▼
WebForms Response
    │
    │
    ▼
WebFormsJS
    │
    │ Executes commands
    ▼
HTML / DOM
Enter fullscreen mode Exit fullscreen mode

This is the fundamental relationship between the Commander and the Executor in WebForms Core.

Availability

WebForms.py 2.1 is available through PyPI.

The package can be found on the WebForms Core project page:

WebForms.py on PyPI

CLI

pip install WFC
Enter fullscreen mode Exit fullscreen mode

Developers can use the package to add the WebForms Core Commander model to Python web applications and communicate with the WebFormsJS Executor running in the browser.

Conclusion

With WebForms.py 2.1, the WebForms Core architecture is available for Python applications through the same Commander–Executor concept.

The Python side uses the WebForms class to create commands, while WebFormsJS executes those commands on the client.

Operations such as:

form.set_text(...)
Enter fullscreen mode Exit fullscreen mode

and:

form.increase(...)
Enter fullscreen mode Exit fullscreen mode

allow server-side Python code to update elements in the existing page without requiring the developer to manually implement JavaScript DOM operations.

The result is a simple division of responsibilities:

WebForms.py — Commander

Creates and sends UI commands from the server.

WebFormsJS — Executor

Receives and executes those commands in the browser.

WebForms.py 2.1 therefore provides a straightforward way for Python developers to work with the WebForms Core architecture while keeping the server-side code focused on application logic and the client-side execution handled by WebFormsJS.

Top comments (0)