Skip to content

Latest commit

 

History

History
157 lines (135 loc) · 5.51 KB

File metadata and controls

157 lines (135 loc) · 5.51 KB

pytypehintweb

PyPI version Python License

Python schemas in. Portable form plans and browser widgets out.

pytypehintweb is a framework-free browser form layer for pytypehint. It converts compiled Python type schemas into self-contained, JSON-serializable form plans and renders them with plain JavaScript widgets. The browser runtime also consumes hand-written plans or plans from another backend, so Python is not required at render time. Everything around the form — routing, static-file delivery, authentication, submission, function execution — belongs to the host application. (For the whole request/response cycle instead of the rendering layer, see FuncToWeb.)

Pre-1.0: the API is still settling, so breaking changes are expected between releases.

Features

  • Self-contained, JSON-serializable plans from plain functions, dataclass types or compiled Signature/Struct schemas — and hand-written plans need no Python.
  • Framework-free browser runtime (plain HTML, CSS and JS modules), with widgets usable directly or from a plan; browser files ship inside the Python package under pytypehintweb.STATIC.
  • Optional stylesheet scoped to a .pth-root container, with a light/dark theme that follows the system or is forced with data-pth-theme — pure CSS, no theme JavaScript and no flash. Its icons are plain .svg files served beside it, so no img-src data: is needed.
  • str, int, float, date, time, bool and enum composing through lists, optional fields, unions and nested dataclasses, with constraints, static choices, integer sliders, and configurable validation messages and labels.
  • file fields (single, optional or list[File], and inside dataclasses) that mint an upload reference the host redeems through its own channel, and that accept an existing reference as a plan default or through setValue().
  • Centralized plan normalization and validation before any widget is built, and plain / inline / wrapped union transport.
  • Plan text is always rendered as text, never parsed as markup.

Installation

pip install pytypehintweb            # library
pip install "pytypehintweb[demo]"    # + the local demo (pytypehintweb-demo)
# Demo with all widgets, served by a local HTTP server on port 8000:
pytypehintweb-demo

There is no npm package: the browser modules live under pytypehintweb.STATIC and can be served by any static-file mount.

Quick start

from typing import Annotated

from pytypehint import Label, Min
from pytypehintweb import plan_of


def create_user(
    username: Annotated[str, Min(3), Label("Username")],
    age: Annotated[int, Min(0), Label("Age")],
) -> None:
    pass


plan = plan_of(create_user)

plan_of() returns ordinary Python dictionaries and lists — a single, fully expanded, self-contained document where every non-conditional property is present with an explicit value (default appears exactly when hasDefault is true), carrying a top-level "v": 1:

{
  "v": 1,
  "kind": "form",
  "name": "create_user",
  "description": null,
  "fields": [
    {
      "name": "username",
      "label": "Username",
      "description": null,
      "optional": false,
      "enabled": true,
      "hasDefault": false,
      "node": {
        "kind": "str",
        "options": {
          "minLength": 3,
          "maxLength": null,
          "pattern": null,
          "patternMessage": "Invalid format",
          "minMessage": "Must contain at least {value} characters",
          "maxMessage": "Must contain at most {value} characters",
          "placeholder": null,
          "password": false,
          "rows": null,
          "choices": null
        }
      }
    },
    {
      "name": "age",
      "label": "Age",
      "description": null,
      "optional": false,
      "enabled": true,
      "hasDefault": false,
      "node": {
        "kind": "int",
        "options": {
          "min": 0,
          "max": null,
          "multipleOf": null,
          "step": null,
          "slider": false,
          "showValue": false,
          "placeholder": null,
          "choices": null,
          "safeMessage": "Must be a safe integer",
          "invalidMessage": "Enter a valid integer",
          "minMessage": "Must be at least {value}",
          "maxMessage": "Must be at most {value}",
          "multipleOfMessage": "Must be a multiple of {value}",
          "increaseLabel": "Increase",
          "decreaseLabel": "Decrease"
        }
      }
    }
  ]
}

Transporting that document to the browser and compiling it with compileForm() is walked through end to end in Getting started.

Documentation