xnano.state
xnano.state
¶
xnano.state
The state of a canvas, a placement and a hook, stored in the core state store.
Classes:
-
StateNamespace–A branch of a canvas's state that hooks and your code read with
getand write withpush.
Functions:
-
parse_path–Split a dotted state path into the keys and indexes it names.
Attributes:
StatePath
module-attribute
¶
A path in the state store: object keys and array indexes, outermost first.
StateNamespace
¶
StateNamespace(canvas: Canvas[object, object], base: StatePath, *, fields: Mapping[str, object] | None = None)
A branch of a canvas's state that hooks and your code read with get and write with push.
A canvas has one state tree. canvas.state (and context.root.state) is its root,
placement.state (and context.buffer.state) is a branch that belongs to one placement,
and context.plugin.state is a branch that belongs to one hook. Each is an independent
namespace, so two hooks can both keep a 'count' without meeting.
Paths are dotted: 'player.score' is the score of player, and a part made only of
digits is an index into a list ('items.0.name'). '' is the namespace itself. Keep
small values here, such as numbers, flags, names and short lists; the state is not a place
for per-cell data.
Inside a hook, a read sees the state as it was when the hook started plus whatever the hook
pushed, and every push is saved together when the hook returns. A hook declared with
on='state' runs again when a path it read changes; other hooks do not.
On the root of a canvas created with new(state=Settings()), the fields of the dataclass
are also attributes with their declared types, and a write is checked against the field's
type. A field that holds a nested dataclass reads as a new instance of that dataclass, so
changing it changes nothing: assign the field or push a path to save a change. A whole
number written to a float field is stored and read as a float.
Attributes:
-
<field>–Every field of the state dataclass, on the root namespace only.
Examples:
import xnano
with xnano.new(width=8, height=1) as canvas:
canvas.state.push('player', {'name': 'Ada'})
canvas.state.push('player.score', 3)
assert canvas.state.get('player.score') == 3
assert canvas.state.get('player.lives', default=0) == 0
@canvas.hook(on='key')
def count(context: xnano.Context) -> None:
state = context.root.state
state.push('player.score', state.get('player.score') + 1)
Create a namespace. Use canvas.state, placement.state or context.plugin.state.
Parameters:
-
canvas(Canvas[object, object]) –The root canvas that owns the state store.
-
base(StatePath) –Where the namespace starts in the store.
-
fields(Mapping[str, object] | None, default:None) –The declared type of every state dataclass field by name, for the root namespace.
Methods:
Source code in xnano/state.py
get
¶
Read the value at path.
Parameters:
-
path(str) –A dotted path such as
'player.score', or''for the whole namespace. -
default(JSONValue, default:None) –What to return when nothing is stored at
path.
Raises:
-
ValueError–pathis malformed.
Examples:
import xnano
with xnano.new(width=8, height=1) as canvas:
canvas.state.push('level', 4)
assert canvas.state.get('level') == 4
assert canvas.state.get('player', default='nobody') == 'nobody'
Source code in xnano/state.py
push
¶
Write value at path, creating the objects on the way.
A name at the root that is not a declared field is added as a new value, so check the spelling of a root path. Inside a declared object, a name that is not one of its fields is refused.
Inside a hook the write is saved when the hook returns; elsewhere it is saved at once. The canvas draws a frame afterwards.
Parameters:
-
path(str) –A dotted path such as
'player.score'.''replaces a whole placement or hook namespace with an object, and is not allowed on the root. -
value(JSONValue) –A number, string, flag,
None, list or dictionary of those.
Raises:
-
ValueError–pathis malformed or names the reservedxnanokey. -
TerminalError–The value does not fit a declared field, or the namespace belongs to a placement or hook that was removed.
Examples:
import xnano
with xnano.new(width=8, height=1) as canvas:
canvas.state.push('score', 1)
canvas.state.push('score', 2)
assert canvas.state.get('score') == 2
canvas.state.push('player', {'name': 'Ada'})
canvas.state.push('player.score', 5)
assert canvas.state.get('player') == {'name': 'Ada', 'score': 5}
Source code in xnano/state.py
parse_path
cached
¶
Split a dotted state path into the keys and indexes it names.
Parameters:
-
path(str) –Parts joined by dots, such as
'player.score'or'items.0.name'. A part made only of digits is an array index.''names the whole namespace.
Raises:
-
ValueError–pathis not a string or has an empty part.