PyPositron Docs

Global Functions

PyPositron provides several global functions that serve as the main entry points for creating and managing PyPositron applications. These functions handle window creation, event loop management, and utility operations.

openUI()

The primary function for creating and displaying a PyPositron window. This is the main entry point for most PyPositron applications.

Signature

openUI(html_path, main=None, after_close=None, width=900, height=700, title="Window", 
       functions=None, x=None, y=None, resizable=True, fullscreen=False, 
       min_size=(200, 100), hidden=False, frameless=False, easy_drag=True, 
       shadow=True, focus=True, minimized=False, maximized=False, on_top=False, 
       confirm_close=False, background_color='#FFFFFF', transparent=False, 
       text_select=False, zoomable=False, draggable=False, vibrancy=False,
       gui=None, debug=False, http_server=False, http_port=None, 
       user_agent=None, private_mode=True, storage_path=None, icon=None) -> PositronWindowWrapper

Parameters

Required Parameters

  • html_path: str: Path to the HTML file to load. This should be relative to your Python script or an absolute path.

Core Application Parameters

  • main: Callable[[PositronWindowWrapper], None] | None: Function to run when the window opens. Receives a PositronWindowWrapper object as parameter. Default: None
  • after_close: Callable[[PositronWindowWrapper], None] | None: Function to run when the window closes. Default: None
  • functions: list | None: List of Python functions to expose to JavaScript. These become available in <py> tags and JavaScript. Default: None

Window Appearance

  • width: int: Window width in pixels. Default: 900
  • height: int: Window height in pixels. Default: 700
  • title: str: Window title shown in the title bar. Default: "Window"
  • background_color: str: Window background color in CSS format. Default: '#FFFFFF'
  • icon: str | None: Path to window icon file. Only supported in Qt/GTK backends. Default: None

Window Position and Size

  • x: int | None: X coordinate of the window position. Default: None (center)
  • y: int | None: Y coordinate of the window position. Default: None (center)
  • min_size: tuple[int, int]: Minimum window size as (width, height). Default: (200, 100)
  • resizable: bool: Whether the window can be resized. Default: True

Window State

  • hidden: bool: Whether the window is initially hidden. Default: False
  • fullscreen: bool: Whether the window starts in fullscreen mode. Default: False
  • minimized: bool: Whether the window is initially minimized. Default: False
  • maximized: bool: Whether the window is initially maximized. Default: False
  • focus: bool: Whether the window has focus when created. Default: True

Window Behavior

  • frameless: bool: Whether the window has no frame/border (no title bar, borders). Default: False
  • easy_drag: bool: Whether frameless windows can be easily dragged. Default: True
  • shadow: bool: Whether the window has a drop shadow. Default: True
  • on_top: bool: Whether the window stays on top of other windows. Default: False
  • confirm_close: bool: Whether to show confirmation dialog when closing. Default: False
  • transparent: bool: Whether the window background is transparent. Default: False
  • vibrancy: bool: Whether the window has vibrancy effect on macOS. Default: False

Content Behavior

  • text_select: bool: Whether text selection is enabled in the webview. Default: False
  • zoomable: bool: Whether content can be zoomed (Ctrl+/Ctrl-). Default: False
  • draggable: bool: Whether the window can be dragged. Default: False

Browser Configuration

  • gui: webview.GUIType | None: GUI toolkit to use. Options: 'qt', 'gtk', 'cef', 'mshtml', 'edgechromium', 'android'. Default: None (auto-select)
  • debug: bool: Whether to enable debug mode (developer tools). Default: False
  • private_mode: bool: Whether to run in private browsing mode. Default: True
  • user_agent: str | None: Custom user agent string. Default: None

HTTP Server

  • http_server: bool: Whether to serve local files using HTTP server instead of file:// protocol. Default: False
  • http_port: int | None: HTTP server port. Default: None (auto-select)

Storage

  • storage_path: str | None: Path for storing browser data (cookies, localStorage, etc.). Default: None

Returns

  • PositronWindowWrapper: A wrapper object providing access to the window and context.

Raises

  • RuntimeError: If not called from the main thread
  • FileNotFoundError: If the HTML file is not found

Usage Examples

Basic Usage

import py_positron

def main(ui):
    ui.document.getElementById("title").innerText = "Hello PyPositron!"

py_positron.openUI("index.html", main=main)

Customized Window

import py_positron

def main(ui):
    # Your app logic here
    pass

def on_close(ui):
    print("Window is closing...")

py_positron.openUI(
    "app.html",
    main=main,
    after_close=on_close,
    width=1200,
    height=800,
    title="My PyPositron App",
    resizable=True,
    background_color="#f0f0f0"
)

Frameless Window

import py_positron

def main(ui):
    # Create custom title bar since window is frameless
    title_bar = ui.document.getElementById("titleBar")
    close_btn = ui.document.getElementById("closeBtn")
    
    def close_window():
        ui.window.destroy()
    
    close_btn.addEventListener("click", close_window)

py_positron.openUI(
    "frameless.html",
    main=main,
    frameless=True,
    easy_drag=True,
    width=800,
    height=600
)

Exposing Python Functions

import py_positron

def calculate_sum(a, b):
    return a + b

def get_system_info():
    import platform
    return {
        "system": platform.system(),
        "python_version": platform.python_version()
    }

def main(ui):
    # Functions are now available in JavaScript and <py> tags
    pass

py_positron.openUI(
    "calculator.html",
    main=main,
    functions=[calculate_sum, get_system_info]
)

Development Mode

import py_positron

def main(ui):
    pass

py_positron.openUI(
    "debug.html",
    main=main,
    debug=True,  # Enables developer tools
    http_server=True,  # Serves files via HTTP
    http_port=8080
)

start()

Starts the webview event loop. This function is typically not needed as openUI() handles this automatically, but it can be useful in advanced scenarios.

Signature

start() -> None

Usage

import py_positron

# This is usually handled automatically by openUI()
py_positron.start()

escape_js_string()

Escapes a string for safe use in JavaScript code. This is useful when dynamically generating JavaScript code or when passing Python strings that may contain special characters.

Signature

escape_js_string(string: str) -> str

Parameters

  • string: str: The string to escape

Returns

  • str: The escaped string safe for JavaScript

Usage Examples

import py_positron

def main(ui):
    user_input = "Hello 'World' with \"quotes\" and \n newlines"
    safe_string = py_positron.escape_js_string(user_input)
    
    # Now safe to use in JavaScript
    js_code = f"console.log('{safe_string}');"
    
    # Or when setting element content
    element = ui.document.getElementById("output")
    element.innerText = safe_string

run_python_code_in_html()

Processes and executes Python code embedded in HTML <py> tags. This function is used internally by PyPositron but can be called manually for advanced use cases.

Signature

run_python_code_in_html(html_content: str, context: PositronContext) -> str

Parameters

  • html_content: str: HTML content containing <py> tags
  • context: PositronContext: The execution context for Python code

Returns

  • str: HTML content with <py> tags processed and executed

Usage

This function is primarily used internally, but understanding it helps when working with <py> tags:

<!-- This gets processed by run_python_code_in_html() -->
<py>
button = document.getElementById("myButton")
button.innerText = "Updated by Python!"
button.style.color = "blue"
</py>

Complete Application Examples

Simple Calculator

import py_positron

def add(a, b):
    return float(a) + float(b)

def subtract(a, b):
    return float(a) - float(b)

def multiply(a, b):
    return float(a) * float(b)

def divide(a, b):
    if float(b) == 0:
        return "Error: Division by zero"
    return float(a) / float(b)

def main(ui):
    # Calculator logic
    display = ui.document.getElementById("display")
    buttons = ui.document.getElementsByClassName("calc-btn")
    
    current_value = ""
    operator = None
    stored_value = None
    
    def update_display():
        display.value = current_value or "0"
    
    def handle_number(num):
        nonlocal current_value
        current_value += str(num)
        update_display()
    
    def handle_operator(op):
        nonlocal current_value, operator, stored_value
        if current_value:
            stored_value = float(current_value)
            current_value = ""
            operator = op
    
    def calculate():
        nonlocal current_value, operator, stored_value
        if stored_value is not None and current_value and operator:
            try:
                if operator == "+":
                    result = add(stored_value, current_value)
                elif operator == "-":
                    result = subtract(stored_value, current_value)
                elif operator == "*":
                    result = multiply(stored_value, current_value)
                elif operator == "/":
                    result = divide(stored_value, current_value)
                
                current_value = str(result)
                operator = None
                stored_value = None
                update_display()
            except Exception as e:
                current_value = "Error"
                update_display()
    
    # Set up button event handlers
    for button in buttons:
        value = button.getAttribute("data-value")
        if value:
            if value.isdigit() or value == ".":
                button.addEventListener("click", lambda: handle_number(value))
            elif value in ["+", "-", "*", "/"]:
                button.addEventListener("click", lambda: handle_operator(value))
            elif value == "=":
                button.addEventListener("click", calculate)
            elif value == "clear":
                def clear():
                    nonlocal current_value, operator, stored_value
                    current_value = ""
                    operator = None
                    stored_value = None
                    update_display()
                button.addEventListener("click", clear)
    
    update_display()

py_positron.openUI(
    "calculator.html",
    main=main,
    title="PyPositron Calculator",
    width=300,
    height=400,
    resizable=False,
    functions=[add, subtract, multiply, divide]
)

File Manager

import py_positron
import os
import json

def get_directory_contents(path):
    try:
        items = []
        for item in os.listdir(path):
            item_path = os.path.join(path, item)
            items.append({
                "name": item,
                "path": item_path,
                "is_directory": os.path.isdir(item_path),
                "size": os.path.getsize(item_path) if os.path.isfile(item_path) else 0
            })
        return items
    except Exception as e:
        return []

def main(ui):
    current_path = os.getcwd()
    path_display = ui.document.getElementById("currentPath")
    file_list = ui.document.getElementById("fileList")
    
    def update_file_list():
        nonlocal current_path
        path_display.innerText = current_path
        file_list.innerHTML = ""
        
        contents = get_directory_contents(current_path)
        
        # Add parent directory option
        if current_path != os.path.dirname(current_path):
            parent_item = ui.document.createElement("div")
            parent_item.className = "file-item directory"
            parent_item.innerText = ".."
            parent_item.addEventListener("click", lambda: navigate_to(os.path.dirname(current_path)))
            file_list.appendChild(parent_item)
        
        # Add files and directories
        for item in contents:
            item_element = ui.document.createElement("div")
            item_element.className = f"file-item {'directory' if item['is_directory'] else 'file'}"
            item_element.innerText = item['name']
            
            if item['is_directory']:
                item_element.addEventListener("click", lambda: navigate_to(item['path']))
            
            file_list.appendChild(item_element)
    
    def navigate_to(path):
        nonlocal current_path
        if os.path.isdir(path):
            current_path = path
            update_file_list()
    
    # Initial load
    update_file_list()

py_positron.openUI(
    "filemanager.html",
    main=main,
    title="PyPositron File Manager",
    width=800,
    height=600,
    functions=[get_directory_contents]
)

Best Practices

  1. Keep the main function focused: Use the main function primarily for UI setup and event binding.

  2. Handle errors gracefully: Always wrap potentially failing operations in try-catch blocks.

  3. Use appropriate window settings: Choose window parameters that make sense for your application type.

  4. Expose only necessary functions: Only expose Python functions to JavaScript that are actually needed.

  5. Clean up resources: Use the after_close callback to clean up any resources when the window closes.

  6. Test different backends: If you encounter issues, try different GUI backends using the gui parameter.

  7. Use debug mode during development: Enable debug mode to access developer tools for easier debugging.

# Good practice example
import py_positron
import logging

def safe_file_operation(filename):
    try:
        with open(filename, 'r') as f:
            return f.read()
    except Exception as e:
        logging.error(f"File operation failed: {e}")
        return f"Error: {str(e)}"

def main(ui):
    try:
        # Initialize UI components
        setup_event_handlers(ui)
        load_initial_data(ui)
    except Exception as e:
        ui.htmlwindow.alert(f"Initialization error: {e}")

def cleanup(ui):
    # Clean up resources
    logging.info("Application closing")

py_positron.openUI(
    "app.html",
    main=main,
    after_close=cleanup,
    debug=True,  # Enable during development
    functions=[safe_file_operation]
)

Related Documentation