JustPy Documentation

repository·master·Indexed 23 days ago

https://github.com/justpy-org/justpy

JustPy is an object-oriented, component-based, high-level Python web framework that allows developers to build interactive websites and GUIs without front-end programming. It leverages Starlette, Uvicorn, and Vue.js to bridge the gap between Python and the browser. The framework includes built-in support for HTML, SVG, Quasar Material Design 2.0, and integrates with pandas, matplotlib, and Highcharts for data visualization. Note: JustPy is being sunsetted as of version 14.0.

Tokens
95.1K
Snippets
198
Records
362
Agent score
78%

What's inside JustPy

  1. What is JustPy?

    master

    JustPy is an object-oriented, component-based, high-level Python web framework designed to create interactive websites and GUIs without requiring front-end programming (JavaScript).

    Key characteristics:

    • No front-end/back-end distinction: All programming is done in Python on the back-end. JustPy intercepts front-end events and sends them to the back-end for processing.
    • Component-based: Web elements are instances of Python component classes. You can build custom reusable components using existing ones as building blocks.
    • Built-in Support: Includes HTML, SVG, charts, grids, and support for the Quasar (Material Design 2.0) library.
    • Data Integration: Integrates with pandas for interactive charts and grids, and supports matplotlib and Highcharts for visualization.
  2. What is JustPy and how does it work?

    master

    JustPy is an object-oriented, component-based Python web framework designed to create interactive websites and GUIs without requiring front-end programming (JavaScript).

    Key Concepts:

    • No Front-end/Back-end Distinction: All programming is done in Python on the back-end. JustPy intercepts front-end events and sends them to the back-end for processing.
    • Component-Based: Web elements are instances of Python component classes. You can create reusable custom components by using existing components as building blocks.
    • Built-in Support: Includes HTML, SVG, charts, grids, and support for the Quasar Material Design 2.0 library.
    • Data Integration: Integrates with pandas via a specialized extension for creating interactive charts and grids from pandas data structures. It also supports matplotlib and Highcharts for visualization.
  3. Sync Tab selection with a Model

    master

    You can bind a Tab component to a model (e.g., a WebPage data dictionary) so that the selected tab ID is automatically synchronized with application state.

    To do this:

    1. Pass the model and the key to the component: model=[wp, 'tab_key'].
    2. The component uses model_update() to check if the model's value has changed externally and updates the visible tab accordingly.
    3. When a tab is clicked, the component updates the model value automatically.
  4. How to create custom components in JustPy

    master

    In JustPy, components are primarily implemented as Python classes that inherit from existing JustPy component classes (like jp.Button, jp.Div, etc.).

    Key Requirements

    • Inheritance: Your custom class must inherit from a JustPy component class.
    • The super().__init__(**kwargs) Rule: You must call super().__init__(**kwargs) inside your component's __init__ method. This ensures the component instance is created correctly.
    • Initialization Order: Only define default values for your custom attributes before calling super().__init__(**kwargs). This allows those defaults to be overwritten by keyword arguments passed during instantiation.

    For highly complex components (like those requiring Quasar or specific charting libraries), you may also need to develop a corresponding Vue.js component, but most custom components can be built using only Python.

  5. Implement reactive state in JustPy components using react()

    master

    In JustPy, you can implement reactive UI updates by overriding the react(self, data) method within a component class. When an event (like a click) modifies the component's internal state, the react method is called to update the component's visual properties (such as self.text).

    To create a reactive component:

    1. Inherit from a JustPy component (e.g., jp.Button, jp.Div).
    2. Define state variables in __init__.
    3. Register event handlers using .on('event_name', handler_method) or the click argument.
    4. Update the UI by modifying component attributes inside the react method.
    import justpy as jp
    
    class ButtonCounter(jp.Button):
        def __init__(self, **kwargs):
            self.count = 0
            super().__init__(**kwargs)
            self.on('click', self.button_clicked)
    
        def button_clicked(self, msg):
            self.count += 1
    
        def react(self, data):
            # This updates the button text whenever the state changes
            self.text = f'You clicked me {self.count} times.'
    
    async def button_counter_demo():
        wp = jp.WebPage(tailwind=False)
        ButtonCounter(a=wp)
        return wp
    
    jp.justpy(button_counter_demo)
  6. How reactivity works in JustPy

    master

    JustPy is a reactive framework, meaning the view updates automatically when the underlying application data changes. Because JustPy runs on the server, reactivity is achieved by converting Python objects into dictionaries that are sent to a Vue-based frontend as JSON.

    There are three levels of implementation:

    1. Static HTML: Generating HTML from data without any event handlers. Changes to the data require a server restart to reflect in the browser.
    2. Manual Reactivity: Using event handlers (like click) to manually manipulate the component tree (e.g., calling .delete_components() and recreating children) on the server side.
    3. Full Reactivity (Components): Defining custom Python classes that inherit from JustPy components. By implementing a react method, you define how the component should render itself based on its current state. When attributes of the component instance change, the framework automatically triggers the rendering process to sync the frontend.
  7. Access the WebPage instance from an event handler

    master

    When an event is triggered, the msg argument contains a page attribute which is a reference to the WebPage instance where the event originated. This allows you to access or modify page-level data, such as a list of all buttons, from within a specific element's handler.

    This is useful for implementing logic like "only highlight the last clicked item" by iterating over a list stored on the page.

  8. How transitions work in JustPy

    master

    JustPy implements transitions using Alpine's transition format. Transitions are triggered by adding or removing the hidden class on an element.

    To make a transition work, you must use the set_class or remove_class methods to toggle the hidden class. If you are not using Tailwind or Quasar, you must ensure the hidden class is defined in your CSS as {display: none;}.

    A transition is composed of three sets of classes applied to three different states:

    1. States:

      • enter: When an element transitions from hidden to not hidden.
      • leave: When an element transitions from not hidden to hidden.
      • load: When the page is initially loaded.
    2. Class Sets per state:

      • Base classes: Associated with the element throughout the entire transition process.
      • Start classes: Define the initial state of the element at the beginning of the transition.
      • End classes: Define the final state of the element after the transition completes.
  9. Show and Hide elements in JustPy

    master

    JustPy provides two distinct ways to manage element presence on a page:

    1. show attribute: A boolean attribute that determines if an element is rendered in the DOM. If show=False, the element is completely removed from the page structure.
    2. Visibility (CSS-based): If you want an element to remain in the page structure (preserving layout/spacing) but be hidden from view, do not use show. Instead, use Tailwind CSS classes like invisible or visible, or manipulate the style attribute.

    Use show for conditional rendering where layout shifts are acceptable. Use CSS visibility classes when you need to maintain the element's footprint on the page.

  10. Implement custom event handlers in components

    master

    You can define custom events for your components (e.g., a change event) that fire when specific internal logic occurs.

    To implement a custom event:

    1. Check for existence: Use has_event_function('event_name') to see if the user provided a handler for that event.
    2. Prepare the message: Create or modify a dictionary (often called msg) containing the event data (e.g., event_type, value, id).
    3. Execute the handler: Use await component.run_event_function('event_name', msg) to trigger the handler.

    Note: Because run_event_function is an async method, any event handler that calls it (like a button click handler) must also be defined as async def.

    Example of triggering a change event:

    if changed:
        if calc.has_event_function('change'):
            calc_msg = msg
            calc_msg.event_type = 'change'
            calc_msg.value = calc.value
            return await calc.run_event_function('change', calc_msg)
    if changed:
        if calc.has_event_function('change'):
            calc_msg = msg
            calc_msg.event_type = 'change'
            calc_msg.id = calc.id
            calc_msg.button_text = self.text
            calc_msg.value = calc.value
            calc_msg.class_name = calc.__class__.__name__
            return await calc.run_event_function('change', calc_msg)
  11. Difference between remove and delete in JustPy

    master

    In JustPy, remove and delete serve different purposes regarding memory management and component lifecycle:

    • remove(component): Removes a component from its parent's component list. It does not remove the component instance from Python memory; it only detaches it from the UI hierarchy.
    • delete(): Removes all internal JustPy references to a component instance, allowing Python's garbage collector to reclaim the memory.

    Important Lifecycle Notes:

    • Automatic Deletion: The framework automatically deletes all components on a page when the browser tab is closed, provided the delete_flag is not set to False. Alternatively, setting a component's show attribute to False will also trigger automatic deletion when the tab closes.
    • Manual Cleanup Pattern: If you manually remove an element from a page, it will not be automatically deleted when the tab closes. To prevent memory leaks, you should remove the component first and then delete it.
    • Recursive Deletion: Calling delete on a component also deletes all of its child components (unless a child has its delete_flag set to False).
    • When to Delete: You only need to worry about deleting components that the user interacts with (e.g., components with explicit event handlers like click, or components with input events used for server-side value updates). Components that are purely static and have no user interaction references do not need manual deletion.
  12. Override the react method for custom components

    master

    Every JustPy component supports a react method. This method is executed immediately before a class instance is converted into a dictionary for rendering. It is the primary way to ensure that a component's visual state (like inner_html or child element properties) stays synchronized with its Python attributes when those attributes change after initialization.

    Key details:

    • Arguments: react receives self and a data argument.
    • The data argument: This is the data attribute of the component's direct parent. If the component has no parent, data refers to the data attribute of the WebPage.
    • Usage: Use react to update self.inner_html, self.text, or the properties of child elements stored as attributes (e.g., self.title_p.text = self.title_text).
    • Precaution: When updating text content in react, it is often recommended to set the parent element's text attribute to an empty string ('') to prevent accidental rendering of raw text alongside your intended HTML structure.
    class MyAlert(jp.Div):
        def __init__(self, **kwargs):
            self.title_text = 'This is the title'
            super().__init__(**kwargs)
            # ... setup child elements ...
            self.title_p = c7 # Store reference to a child element
    
        def react(self, data):
            # Update child element properties based on current instance state
            self.title_p.text = self.title_text
            self.text = ''