Skip to content

Releases: MaanavKrishna/PyWeb

PyWeb 0.4.3

Choose a tag to compare

@MaanavKrishna MaanavKrishna released this 04 Oct 07:10

A review release: bug fixes, security hardening and speed-ups. No API
removals; one new setting (PYWEB_TRUST_PROXY).

Fixed

  • Pages showed stale data when a module-level value (ITEMS = []) was
    changed by an @server function: the compiler copied its starting
    value into browser code, and the page re-rendered with it. Values
    that code changes now come from the server on each request.
  • db.transaction(): a statement error that your code caught rolled
    back the transaction's earlier writes while later ones still
    committed. Errors inside a transaction now leave it to
    transaction() (all or nothing).
  • db.stream() inside a transaction waited for a second connection
    (a 10 second hang with SQLite in memory); it now uses the
    transaction's.
  • pyweb serve sent SVG, images, fonts, JSON and WebAssembly as
    application/octet-stream (browsers don't show an SVG sent that way).
  • Your own files in static/ (such as app.css) were cached by
    browsers for a year, so deploys didn't show up for returning
    visitors. They're now revalidated with an ETag (a 304 when
    unchanged); content-hashed files, ?v= URLs and npm packages are
    still cached for a year.
  • Client-side navigation could show a page prefetched before a server
    call changed its data.
  • async def server functions ignored rpc_timeout.
  • The ASGI adapter kept only the last of repeated request headers, so
    HTTP/2 clients sending each cookie separately lost all but one.
  • pyweb dts: type aliases were never written, members on one line
    ({ a: string; b?: number }) produced invalid Python, and optional
    fields before required ones made the stub fail to import.
  • Very long upload filenames are shortened (keeping the extension)
    instead of failing to save.

Security

  • RPC rate limits used the X-Forwarded-For header, which any client
    can set (so the limit was easy to get around), and put every visitor
    without a session cookie in one shared bucket. They now use the
    connection's address; behind a reverse proxy set PYWEB_TRUST_PROXY=1
    (or the number of proxies) to use the address your proxy saw.
  • auth.require_session and auth.login_response only redirect to
    paths on your site (//evil.example becomes /); the new
    auth.safe_next() does the same for your own ?next= handling.
  • Magic-link tokens are signed separately from session cookies, so one
    can't be used as the other. Links issued before the upgrade stop
    working (they last 15 minutes).

Performance

  • HTML, JavaScript, CSS, JSON and SVG are gzipped for browsers that
    accept it (the shared runtime goes from 46 KB to 15 KB); static files
    are compressed once and kept.
  • Memory no longer grows without bound in long-running servers: the
    rate limiter forgets idle callers, the realtime bus forgets channels
    quiet for an hour, the in-memory cache drops expired entries, and
    the job queue forgets jobs an hour after they finish.
  • The job queue runs jobs on a pool of 8 threads instead of one thread
    per job, and wait() returns as soon as the job finishes.
  • pyweb dev no longer re-scans virtualenvs in the project folder
    every 0.4 s, and reloads when pyweb.lock changes (after
    pyweb add).

PyWeb 0.4.2

Choose a tag to compare

@MaanavKrishna MaanavKrishna released this 03 Oct 18:14

Added

  • VS Code extension: PyWeb: Run App (a run button on .pyweb
    files, Ctrl+F5), New App from any template, Check App, Add
    npm Package
    , Install or Update PyWeb and Set Up AI Assistant
    (MCP)
    , which adds the PyWeb MCP server to .vscode/mcp.json.
  • VS Code extension: closing tags are added as you type, Emmet works in
    markup, new snippets (layout, error, stream, livequery, npm,
    mount), a status item that shows the PyWeb version in use, and an
    icon.

Fixed

  • VS Code extension: the language server failed with
    spawn python ENOENT when no Python interpreter was selected. The
    extension now looks for a Python with PyWeb (the selected
    interpreter, pyweb, py, python3, python), offers to install
    PyWeb when it's missing, and restarts when you change interpreter.

PyWeb 0.4.1

Choose a tag to compare

@MaanavKrishna MaanavKrishna released this 03 Oct 16:57

Added

  • MCP server: pyweb_routes maps every page (route, path and query
    parameters with types and defaults, title and head tags, layouts,
    live-data variables), the layouts, error pages and server functions.
  • MCP server: pyweb_packages adds, removes or lists npm packages for
    browser code, with each package's exported names and the npm(...)
    lines to bind them.
  • MCP server: add_ai_feature and make_data_live prompts.
  • MCP server: pyweb_call returns every chunk a streaming function
    yields; pyweb_render reports the title, head tags and the layouts that
    rendered; pyweb_check reports layouts, live variables, npm packages
    and streaming functions.
  • The AI guide (pyweb_guide, AGENTS.md) has sections with working
    examples for multi-page apps, streaming and AI, live data and npm
    packages.
  • A new README with screenshots, and docs on publishing the VS Code
    extension.

Fixed

  • Markup right after a def line that ends in a comment
    (def Page(q: str = ""): # ...) failed to compile.

PyWeb 0.4.0

Choose a tag to compare

@MaanavKrishna MaanavKrishna released this 03 Oct 14:20

Apps that are bigger, livelier and smarter: npm packages without
Node.js, multi-page apps with layouts and client-side navigation,
streaming for AI features, and page data that follows the database.

Added

  • npm packages without Node.js. pyweb add chart.js/auto downloads a
    package from the npm registry, checks its sha512 checksum, follows its
    imports from the browser entry point and copies only the files it
    needs (and its dependencies) into static/vendor/, pinning versions in
    pyweb.lock. pyweb add with no arguments reinstalls from the lock;
    pyweb remove takes a package out. Browser code binds exports with
    Chart = npm("chart.js/auto") or npm("pkg", "Export"). Calling a
    class constructs it and keyword arguments become an options object.
    Each page imports only the packages it uses, through an import map
    that the Content Security Policy allows by hash. CommonJS-only and
    Node.js-only packages are refused with an explanation, and an
    uninstalled package is a compile error that names the command to run.
  • ref={el} sets a page variable to an element, in time for
    on_mount, for libraries that draw into the page.
  • Changing an attribute of a package's object (chart.value = 5)
    re-renders whatever shows it.
  • Web components (custom elements from npm) work in markup.
  • pyweb lsp: hover shows an npm binding's installed version and
    TypeScript signature; completion offers installed packages in
    npm(" and a module's exports after name..
  • New docs page: npm packages.
  • Layouts. @app.layout wraps every page (or, with
    @app.layout("/admin"), pages under a prefix) in shared markup;
    {children} marks where the page goes. Layouts nest, have their own
    server code, state and handlers, and pages can opt out with
    layout=None or pick one with layout="Name".
  • Client-side navigation. Links between pages fetch the next page's
    HTML and swap it in below the layouts both pages share, so layout
    state (an open menu, a player) survives. Links are prefetched on
    hover or focus, back/forward restore the scroll position, and anything
    unusual falls back to a full page load. navigate("/path") from
    pyweb.browser does the same from browser code; on_unmount runs
    when a page is left; App(client_nav=False) turns it off.
  • Current links. Links to the current page get
    aria-current="page" and links to its parent sections
    aria-current="true", on the server and after each navigation.
  • Head tags. @app.page(description=..., image=..., noindex=...) and
    head(title=..., description=...) in page code add description, Open
    Graph and Twitter tags; App(base_url=...) adds canonical URLs and
    absolute image links.
  • Error pages in .pyweb. @app.error(404) / @app.error(500) pages
    take path, status, message or request_id and use root layouts.
  • Typed query parameters. Page parameters that aren't in the route
    are read from the query string and converted by annotation (int,
    float, bool, list[...]); bad or missing values answer 400.
  • New docs page: Layouts & navigation.
  • Streaming server functions. A @server function that yields
    sends each value as it's produced (NDJSON over the same RPC endpoint);
    browser code reads it with async for. stream.cancel() or leaving the
    loop aborts the request and closes the generator on the server, so an
    upstream AI call stops too. Errors raised part-way arrive as
    RPCError. Works with async def generators, under pyweb serve,
    pyweb dev and ASGI, and TestClient.rpc returns the streamed values.
  • <Markdown text={...} /> (from pyweb) renders Markdown to safe
    HTML on the server and updates it in the browser as the text changes,
    with the same rules in both places. Raw HTML is shown as text and
    links only accept http(s), mailto and relative URLs.
  • ai-chat template and example: a streaming chat with Stop and
    Markdown replies that talks to Anthropic, any OpenAI-compatible server
    (OpenAI, Ollama, vLLM, ...) or a built-in demo model, chosen by
    environment variables. pyweb new NAME --template ai-chat.
  • New docs page: Building AI apps.
  • Live data. rows = live(db, "select ...", params) in a page or
    layout renders the rows and keeps them current: writes through
    pyweb.db (and pyweb.models) announce their table after commit, each
    distinct query re-runs once per change (bursts coalesced) and sends
    rows to every page showing it only when they changed. Pages follow a
    signed feed; db.notify("table") covers writes made elsewhere. With
    RedisBus it works across processes, and any process can take over a
    query from the page's signed description.
  • New docs page: Live data.
  • watch(lambda: value, handler) (from pyweb.browser) runs a
    handler whenever a value changes, for work outside markup such as
    redrawing a chart or saving a draft.
  • pyweb add applies packages' browser field (browser versions of
    files, modules turned off), so packages such as ethers install.
  • New examples: dashboard (live queries and a Chart.js chart from
    npm), site (layouts, navigation, query parameters, a 404 page) and
    ai-chat. The playground has the site and AI chat examples.
  • New docs page: Recipe: wallets & web3 (wallet sign-in with ethers and
    eth-account).
  • A layout's {children} can sit on a line of its own.

Fixed

  • Subscriptions and cleanups set up in on_mount now end when the page
    is left (they were never stopped).

Changed

  • The experimental pyweb.live module (in-memory live tables) is now
    pyweb.livetable; pyweb.live is the new live-query function.
  • pyweb.npm (TypeScript declarations to dataclasses) is now
    pyweb.dts, and its command is pyweb dts. pyweb build no longer
    writes an esm.sh import map; packages come from pyweb.lock.
  • The default Content Security Policy adds worker-src 'self' blob: so
    packages can start Web Workers.
  • The starter stylesheet styles Markdown and chat bubbles.
  • The browser runtime is about 14 KB gzipped (was about 11 KB), for
    client-side navigation and npm support.
  • New website design: a colour system where blue means the browser and
    amber the server, self-hosted Inter / Bricolage Grotesque / JetBrains
    Mono, dark code windows, and a landing page that shows each line of an
    app with where it runs (worked out by the compiler) next to the real
    compiled output.
  • The example apps and the pyweb new stylesheet use the new palette.

PyWeb 0.3.0

Choose a tag to compare

@MaanavKrishna MaanavKrishna released this 03 Oct 06:26
15d3a36

Faster pages that feel like an app, apps that span several files, and
tools for editors, the browser and AI assistants.

Added

  • Hydration. Pages now adopt the server-rendered DOM instead of
    rebuilding it: nodes are kept, focus and text typed before the script
    loads survive, and typed values reach their variables. When the server
    HTML doesn't match, the page falls back to a client render and logs
    a warning. The page root carries data-pw-mode="hydrated" or
    "rendered".
  • Live updates. publish(name, data) in server code pushes to every
    page that called subscribe(channel_feed, handler), over Server-Sent
    Events with a polling fallback. Feeds come from channel(name) while
    rendering: signed, expiring, and positioned so no message published
    after the render is missed. pyweb dev, pyweb serve and the ASGI
    adapter stream; realtime.use_bus() shares the bus (e.g. Redis)
    between processes. The chat example uses it instead of polling.
  • Multi-file apps. from widgets import Card, save, COLOR imports
    components, @server functions and constants from widgets.pyweb (or
    ui/cards.pyweb as ui.cards). Each file keeps its own names in the
    generated JavaScript, imported files run as real modules on the
    server, pyweb build copies them into dist/, and errors name the
    file they're in. Pages stay in the app file; circular imports and
    duplicate server-function names are compile errors.
  • Editor support. pyweb lsp is a language server (stdio, standard
    library only): compile errors and security warnings as you type,
    hover showing where each name runs and why, completion for components,
    props and tags, go to definition across files, and an outline. The new
    VS Code extension (editors/vscode) adds highlighting and snippets and
    starts it; releases attach a .vsix. Setup for Neovim and Helix is in
    the command-line docs.
  • Playground on the website: edit an app and run it in the browser,
    with the real compiler, server rendering, @server functions,
    sessions and live updates running on Pyodide. Shows the compiled
    JavaScript and what runs where, reports errors with a fix, and shares
    code as links.
  • MCP tools pyweb_screenshot (open a page in headless Chromium,
    run click/fill/press steps, get a screenshot, the page text, console
    errors and hydration status) and pyweb_test (run the app's pytest
    tests and report failures). New apps include a starter test_app.py.
  • python -m pyweb.bench --max-ssr-ms N --max-compile-ms N fails when
    a benchmark exceeds its budget; CI runs it.

Removed

  • The old pyweb.lsp helper functions (complete, DocumentState,
    complete_*, diagnostics_for_compile_error, hover(compiled, name),
    boundary_lens); they described an earlier API and no editor used them.

Changed

  • import pyweb no longer needs the sqlite3 module (it's imported when
    a SQLite database is opened), and password hashing falls back to a
    pure-Python PBKDF2 on Pythons without OpenSSL. Both make PyWeb run on
    Pyodide.
  • /__pyweb/events and /__pyweb/poll require a signed ?feed=; the
    unauthenticated ?channel= form is gone, so channels are no longer
    readable by anyone who guesses a name.
  • Server rendering caches compiled template expressions; rendering a
    page is about twice as fast.
  • Generated page modules pass element children as a function and wrap
    every child in a call ($t, $dyn), so nodes are created in document
    order.

PyWeb 0.2.0

Choose a tag to compare

@MaanavKrishna MaanavKrishna released this 02 Oct 21:16
95e9f35

Tools for building PyWeb apps with AI assistants.

Added

  • pyweb mcp: a Model Context Protocol server (stdio, standard library
    only) for Claude Code, Cursor, Claude Desktop, VS Code and other MCP
    clients. Tools: pyweb_guide, pyweb_new_app, pyweb_check (errors
    with line numbers and fix hints), pyweb_inspect, pyweb_compiled,
    pyweb_render and pyweb_call (session cookies persist between calls);
    resources for the guide and templates; a build_pyweb_app prompt.
    Tested against the official MCP Python SDK.
  • An AI-oriented guide to writing .pyweb apps, shipped in the package.
  • pyweb new --template blank|counter|todo|blog|auth|chat; new projects
    include AGENTS.md and CLAUDE.md for coding agents.
  • The docs site publishes llms.txt and llms-full.txt, and has a new
    "AI assistants & MCP" page.

PyWeb 0.1.0

Choose a tag to compare

@MaanavKrishna MaanavKrishna released this 02 Oct 20:58
1685539

The first public release, published on PyPI as pyweb-stack. The
unpublished prototype was labelled "1.0" but only the simplest counter
pattern worked in a browser; this release rebuilds the compiler, runtime
and server around a design that works end to end, and is verified in a
real browser.

Language and compiler

  • .pyweb parser with a character scanner: tags and expressions may span
    lines, braces and strings nest inside {...}, elif chains, HTML
    comments, and exact line numbers (the Python half keeps the source's
    line count; this also fixes crashes on Python 3.10/3.11).
  • Python → JavaScript translation of a documented subset with Python
    semantics (truthiness, == on containers, negative indexing, floor
    division/modulo, string/list/dict/set methods, Python exceptions).
    Unsupported code is a compile error with file:line. Verified
    differentially against CPython.
  • State inference: signals (mutated by handlers or bound), computeds,
    constants; initial values from literals, the browser, or the server.
    Mutations (append, item assignment, del, …) are copy-on-write.
  • Components with props, defaults and children; on_mount hook;
    page titles; App(title=, stylesheets=, lang=).
  • @server calls from handlers compile to awaited typed RPC; async
    propagates through handler calls.
  • Only values browser code reads are serialised; values derived from
    server data are computed on the server. Secret-looking names read by
    browser code are rejected.

Runtime

  • New browser runtime: dependency-tracked signals, cached computeds,
    owned effects with disposal, batching; keyed lists and conditionals in
    marker-bounded regions; two-way binding for text, number, checkbox,
    radio and select; javascript: URL blocking; RPC client with typed
    errors.

Server

  • Pages render per request with real server values; request,
    session, redirect, NotFound; typed route parameters.
  • @server functions are registered automatically in dev, serve,
    tests and ASGI.
  • New ASGI adapter: pyweb.asgi.create_app.
  • RPC: JSON-only and same-origin checks, rate limiting, timeouts that
    actually return on time, async functions, JSON conversion for
    dataclasses/datetimes/Decimals.
  • Content-Security-Policy and security headers on HTML responses.

Tooling

  • pyweb dev: live reload and an in-browser compile-error overlay.
  • pyweb build produces a self-contained dist/ (source, manifest with
    gzip sizes, hashed assets, working Dockerfile); pyweb serve runs it.
  • Token-aware JS minifier (the previous one altered string literals).
  • pyweb.testing.TestClient and pyweb.testing.serve for tests.
  • Clean file:line: message compile errors from the CLI.

Data, auth, jobs

  • ? placeholders work on Postgres and MySQL; lazy connection pools.
  • WebAuthn: challenge, origin and sign-count checks; DER signatures; uses
    cryptography when installed.
  • Redis bus and queue work against real Redis.

Fixed

  • Migrations: the pyweb_migrations journal table can now be created on
    MySQL (VARCHAR(255) key instead of TEXT).
  • pyweb serve crashed on startup (logger misconfiguration).
  • Production builds referenced a hashed runtime the page modules never
    imported.
  • Installed packages were missing the browser runtime file.
  • transaction() did not roll back on Postgres/MySQL pools.
  • sqlite:///file.db pointed at the filesystem root.
  • RedisBus.since() duplicated and mis-ordered messages;
    RedisQueue.drain(timeout=0) blocked forever.
  • Jobs raising TypeError ran twice.
  • Query.order_by() ignored -field and did not validate a single field.
  • The deploy Dockerfile ran a non-existent serve --dir flag.

Removed

  • Modules the framework no longer uses: pyweb.components (pure-Python
    element API), pyweb.routing (unused router), pyweb.reactive
    (server-side Signal/Computed/Effect/live), and
    pyweb.compiler.placement (superseded by the compiler's boundary checks).
  • The @browser and @shared decorators, which had no effect.
  • pyweb.compiler.rpc.client_stub/server_handler and unused AST classes.
  • docs/BUGLOG.md (it described the prototype's internals) and the committed
    website/dist/; the Pages workflow builds the site.
  • The regex-based codegen, the virtual test client that only recorded
    clicks, documentation "snippets" that did not use PyWeb, island and
    streaming-SSR string helpers without runtime support, and the no-op
    --security-scan flag.