State schema - Writer AI Studio

Schema declaration

import writer as wf

class AppSchema(wf.WriterState):
    counter: int

initial_state = wf.init_state({
    "counter": 0
}, schema=AppSchema)

# Event handler
# It receives the session state as an argument and mutates it
def increment(state: AppSchema):
    state.counter += 1

Accessing an attribute by its key is always possible.

def increment(state: AppSchema):
    state["counter"] += 1

Attributes missing from the schema remain accessible by their key.

initial_state = wf.init_state({
    "counter": 0,
    "message": None
}, schema=AppSchema)

def increment(state: AppSchema):
    state['message'] = "Hello pigeon"

Schema composition

Schema composition allows you to model a complex Application state.

class MyappSchema(wf.State):
    title: str

class AppSchema(wf.WriterState):
    my_app: MyappSchema
    counter: int

initial_state = wf.init_state({
    "counter": 0,
    "my_app": {
        "title": "Nested value"
    }
}, schema=AppSchema)

Calculated properties

Calculated properties are updated automatically when a dependency changes. They can be used to calculate values derived from application state.

class MyAppState(wf.State):
  counter: List[int]

class MyState(wf.WriterState):
  counter: List[int]

@wf.property(['counter', 'app.counter'])
  def total_counter(self):
    return sum(self.counter) + sum(self.app.counter)

initial_state = wf.init_state({
    "counter": 0,
    "my_app": {
        "counter": 0
    }
}, schema=MyState)

Multi-level dictionary

Some components like Vega Lite Chart require specifying a graph in the form of a multi-level dictionary. A schema allows you to specify that an attribute which contains a dictionary must be treated as a dictionary, rather than as a group of state.

class AppSchema(wf.WriterState):
    vegas_graph: dict

# Without schema, this handler is execute only once
def handle_vega_graph(state: AppSchema):
    graph = state.vega_graph
    graph["data"]["values"][0]["b"] += 1000
    state.vega_graph = graph

initial_state = wf.init_state({
    "vegas_graph": {
        "data": {
            "values": [\
                {"a": "C", "b": 2}, {"a": "C", "b": 7}, {"a": "C", "b": 4},\
                {"a": "D", "b": 1}, {"a": "D", "b": 2}, {"a": "D", "b": 6},\
                {"a": "E", "b": 8}, {"a": "E", "b": 4}, {"a": "E", "b": 7}\
            ]
        },
        "mark": "bar",
        "encoding": {
            "x": {"field": "a", "type": "nominal"},
            "y": {"aggregate": "average", "field": "b", "type": "quantitative"}
        }
    },
}, schema=AppSchema)

Type checking

A schema allows you to check the integrity of your back-end using the type system. The code below will raise an error with mypy.

$ mypy apps/myapp/main.py
apps/myapp/main.py:7: error: "AppSchema" has no attribute "countr"; maybe "counter"?  [attr-defined]

Here is the code, can you spot the error ?

import writer as wf

class AppSchema(wf.WriterState):
    counter: int

def increment(state: AppSchema):
    state.countr += 1

initial_state = wf.init_state({
    "counter": 26,
}, schema=AppSchema)