Skip to main content

Python state, React UI.

Project description

RemoteState - Python Library

CI PyPI version Python FastAPI pydantic Ruff License: MIT

remotestate is the Python runtime for RemoteState apps. It owns the state store, service methods, and server that expose Python state to React.

If you want the high-level product overview, start with the repository root README: RemoteState

Install

pip install remotestate

Or with pixi:

pixi add remotestate

Development

  • Python >= 3.12
  • from the package directory: cd remotestate-py
  • install dependencies with pixi install
  • run tests with pixi run tests
  • lint with pixi run lint
  • format with pixi run format
  • reorder imports with pixi run isort
  • type-check with pixi run mypy
  • build a wheel with pixi run build

Quick Start

import remotestate as rs


class CounterService(rs.Service):
    def __init__(self) -> None:
        super().__init__(rs.Store({"count": 0, "user": {"name": "forman"}}))

    @rs.action
    async def increment(self) -> None:
        self.store.set("count", self.store.get("count") + 1)

    @rs.query
    async def compute(self, x: float) -> float:
        self.notify(name="Computing", detail="reading current count", progress=50)
        return x * self.store.get("count")


rs.serve(CounterService(), ui_dist="my-ui/dist")

API Overview

The public Python API is exported from remotestate:

  • Store
  • Service
  • ServeResult
  • action
  • query
  • serve
  • path

Store

Store(initial, *, default_factory=None) holds the Python-side application state.

  • the root state is a mapping

  • nested dicts, lists, Pydantic models, and dataclasses are all supported

  • default_factory receives the missing prefix as a rs.path.Path tuple

  • get(path, require=False) reads a value from a path such as user.name or items[0].label

  • set(path, value) writes a value and notifies subscribers

  • subscribe(callback) receives batched path-to-value updates after changes flush

  • default_factory can materialize missing parents while setting nested values

import remotestate as rs


class User:
    def __init__(self, name: str = "", city: str = "") -> None:
        self.name = name
        self.city = city


def defaults(path: rs.path.Path):
    if path == (rs.path.Property("user"),):
        return User()
    if path == (rs.path.Property("items"),):
        return []
    return {}


store = rs.Store({}, default_factory=defaults)
store.set("user.city", "Hamburg")
store.set("items[0].label", "foo")

assert store.get("user.city") == "Hamburg"
assert store.get("items") == [{"label": "foo"}]

get() never calls the default factory. Reads stay side-effect free, and missing values return None unless require=True is passed.

Actions and Queries

Use @action for state-changing service methods and @query for read-only methods.

  • @action batches store.set() calls and flushes them as one action_result message.
  • @query is read-only; mutating the store inside a query raises PermissionError
  • sync and async methods are both supported
class Counter(rs.Service):
    def __init__(self) -> None:
        super().__init__(rs.Store({"count": 0}))

    @rs.action
    def increment(self) -> None:
        self.store.set("count", self.store.get("count") + 1)

    @rs.query
    async def multiply(self, x: float) -> float:
        self.notify(name="Working", progress=25)
        return x * self.store.get("count")

Service Helpers

Service also provides built-in methods that power the generic TypeScript bridge:

  • get(path) reads a store value by path
  • set(path, value) writes a store value by path
  • notify(name=None, detail=None, progress=None) emits update_task progress messages for tracked calls

The reserved service method names are get, set, and notify. Do not reuse those names for custom actions or queries.

Service._init_app(app) can be overridden to customize the FastAPI app when serve() creates one.

Serving

serve(service, *, ui_dist, mounts, app, display, width, height, host, port, **uvicorn_settings) starts the RemoteState server and connects it to a frontend bundle.

  • service is a Service instance
  • ui_dist can be a local React build directory or an HTTP(S) URL
  • mounts adds additional static paths
  • app lets you supply your own FastAPI app
  • display controls how the UI is shown: "auto", "browser", "notebook", "none", or a callback
  • host and port configure the backend server

By default, RemoteState chooses a free port, opens a browser outside notebooks, and renders inline inside notebooks. Re-running the same notebook cell restarts the server automatically.

serve() returns a ServeResult with the resolved URLs and server handles:

result = rs.serve(CounterService(), ui_dist="my-ui/dist", display="none")

print("Server URL:    ", result.server_url)
print("WebSocket URL: ", result.ws_url)
print("UI Base URL:   ", result.ui_base_url)

Paths

remotestate.path exposes the parsed path types used by Store.default_factory and other advanced integrations:

  • Path
  • Property
  • Index

RemoteState paths use a simplified JSONPath subset without the "$." prefix:

  • the root segment is an identifier
  • later segments may be dotted identifiers, bracketed integer indices, or bracketed JSON string keys
  • bracketed string keys may use either single or double quotes; canonical output uses double quotes
  • the whole string must match the grammar; prefix parsing is not allowed
Example Valid? Notes
user yes root identifier only
items[0].label yes dotted identifier plus integer index
user["display name"] yes bracketed string key
$.user no "$." prefix is not part of the syntax
["root"] no root must be an identifier
items[01] no indices are canonical integers without leading zeroes

Use parse_path() and format_path() when you need to inspect, validate, or construct paths.

More Docs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

remotestate-0.2.0.tar.gz (71.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

remotestate-0.2.0-py3-none-any.whl (21.5 kB view details)

Uploaded Python 3

File details

Details for the file remotestate-0.2.0.tar.gz.

File metadata

  • Download URL: remotestate-0.2.0.tar.gz
  • Upload date:
  • Size: 71.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for remotestate-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7b9cb4291de2e7cb04a54c3e2a98bbc2af9d239764aa8f3b07bd3f4f5665b6fa
MD5 ebc03cf02231305fc00bc32c7e8d67b3
BLAKE2b-256 eb50bd94bec07b0df2e108bd31a3df33e77c43bb69491042c3dd852ecd6a8dfc

See more details on using hashes here.

File details

Details for the file remotestate-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: remotestate-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 21.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for remotestate-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e3167cab9a3b8156018d765177d076bfd25bb24db3dfe590a3b1b6e3e3b8e941
MD5 85b49a88253539726261831994f1fa72
BLAKE2b-256 463b7855608a710a9c32927d2c747e581590da170133632c8dd2a56602304494

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page