Skip to main content

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
  • format with pixi run format
  • run checks with pixi run checks
  • run tests with pixi run tests
  • 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 and StoreAt
  • Service and ServeResult
  • action and query
  • serve
  • path

Store and StoreAt

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

  • the root state may be any JSON-serializable value, including a mapping, list, scalar, Pydantic model, or dataclass

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

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

  • state returns the current root state value

  • get(path=(), require=False) reads a value from a path such as ``, user.name, `[0].label`, or `items[0].label`; omit `path` to read the root state value

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

  • store[path] and store[path] = value are notebook-friendly aliases for get() and set()

  • store.at returns a notebook-friendly accessor of type StoreAt for nested state variables using item or attribute syntax

  • store.at.some.path = value for example executes nested set() calls; use item syntax for arrays or keys that are not valid identifiers

  • 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 == ("user",):
        return User()
    if path == ("items",):
        return []
    return {}


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

assert store.get("user.city") == "Berlin"
assert store.get() is store.state
assert store["items"] == [{"label": "baz"}]
assert store[()] is store.state

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 exposes the store and progress helper used by actions and queries:

  • notify(name=None, detail=None, progress=None) emits update_task progress messages for tracked calls

The reserved service method name is notify. Store reads and writes use service.store.get(...) and service.store.set(...); get and set remain available 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, cors_origins, 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
  • cors_origins optionally allows browser HTTP requests from specified origins; cross-origin HTTP access is disabled by default
  • 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)

Cross-origin access

When the frontend is hosted on a different origin, explicitly allow that origin:

rs.serve(
    CounterService(),
    ui_dist="https://ui.example.com",
    cors_origins=["https://ui.example.com"],
)

Only list origins you trust. cors_origins enables all HTTP methods and request headers for the listed origins, while leaving CORS disabled for every other origin.

Paths

remotestate.path exposes the parsed path types used by Store.default_factory and other advanced integrations. Parsed paths are tuples of string property names and integer array indices, matching the TypeScript package's string | number path segments:

  • Path
  • PathSegment
  • PathInput
  • PathSegmentInput

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

  • the empty string addresses the root state value
  • the first segment may be an identifier, bracketed integer index, or bracketed JSON string key
  • 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
empty string yes root state value
user yes root property shorthand
[0].label yes array root plus child property
items[0].label yes dotted identifier plus integer index
["display name"].value yes bracketed string key at the root
user["display name"] yes bracketed string key
$.user no "$." prefix is not part of the syntax
items[01] no indices are canonical integers without leading zeroes

Use normalize_path() when accepting raw path inputs, and use parse_path() and format_path() when you need to inspect, validate, or construct string paths.

More Docs

Metadata

Release files for remotestate 0.3.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for remotestate 0.3.4
File Size Uploaded Provenance
remotestate-0.3.4.tar.gz 80.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for remotestate 0.3.4
File Interpreter ABI Platform
remotestate-0.3.4-py3-none-any.whl Python 3 none any Details

Total release size: 104.9 kB

Release files / remotestate-0.3.4.tar.gz

Download URL remotestate-0.3.4.tar.gz
Size 80.5 kB
Tags Source
SHA-256 checksum
How to use checksums
f9fbe1a2914125dbb9e3e0f54a26d3d0395b49decb075a3b61feb8c588992c7b
BLAKE2b-256 checksum
How to use checksums
f1922b4ed5079bb489f091dd260386192ea0f8030c607a21096f61d6ff3dd095
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Release files / remotestate-0.3.4-py3-none-any.whl

Download URL remotestate-0.3.4-py3-none-any.whl
Size 24.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
33b173adb0a74727032896c4ea7547920f1ac06137452f3db5289680bb24e0ea
BLAKE2b-256 checksum
How to use checksums
874418ca9a090acc7bf5eb1fbdbb9ad3cb2e73fd56690438a037f5374ec288c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Security for remotestate 0.3.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page