bootstack.Signal#

class bootstack.Signal(value, name=None, master=None, *, allow_empty=False, dtype=None)#

Bases: Generic[T]

A reactive value that widgets can bind to.

Holds a typed value and notifies subscribers when it changes. Read it by calling the signal, update it with set(), derive new signals with map(), and react to changes with subscribe().

Bind a signal to a widget by passing it as textsignal= for text-bearing widgets, or signal= for boolean and numeric widgets.

A signal holds one type, decided by the value it is created with. Pass allow_empty=True when the value can also be empty — a field bound to it reports being cleared, where one bound to an ordinary signal silently keeps its last value. Call clear() to empty a signal. It empties to None, except where its value lives in a widget’s own variable, which holds only strings and so empties to ''. A signal that allows empty may start empty, in which case there is no value to read a type from and dtype= names it.

Signals may be constructed at module level (before bs.App() exists). The backing Tk variable is created lazily on the first widget binding and torn down when the App is destroyed, so the same signal can be reused across successive App lifecycles.

property allows_empty: bool#

Whether this signal can hold an empty value.

A signal that allows empty accepts clear(), so a field bound to it reports being cleared instead of silently keeping its last value. Declare it at construction with bs.Signal(value, allow_empty=True).

property type: Type[T]#

The type of the signal value — the seed’s type, or a declared dtype.

__call__()#

Get the current value of the signal.

clear()#

Set the signal to its empty value and notify subscribers.

The signal must have been declared allow_empty=True. It clears to None, except where its value lives in a widget’s Tk variable — a variable holds only strings, so there it clears to '' — and to the empty set on a set-typed signal.

Raises:

TypeError – If the signal was not declared able to be empty.

map(transform)#

Create a derived signal that transforms this signal’s value.

The derived signal recomputes whenever this signal changes. It is held weakly, so keep a reference to it — for example, by binding it to a widget — or it will stop updating once garbage-collected.

Parameters:

transform (Callable[[T], U]) – A function applied to the current and future values.

Returns:

A new read-only signal that stays updated with the transformed value.

Return type:

Signal[U]

set(value)#

Set the signal to a new value and notify subscribers.

In general, the value must match the signals types, however, an int may be set on a float-typed signal (it is widened), and None is accepted on a signal declared allow_empty=True.

Parameters:

value (T) – The new value. Must match the signal’s type.

Raises:

TypeError – If the value type does not match the signal’s type (and is not an int widened to a float), or if it is None on a signal that was not declared able to be empty.

subscribe(callback, *, immediate=False)#

Subscribe to value changes of this signal.

Parameters:
  • callback (Callable[[T], Any]) – A function called with the new value whenever it changes.

  • immediate (bool) – When True, also call callback once with the current value at subscription time. Defaults to False.

Returns:

A cancellable Handle — call .cancel() to stop listening, or use it as a context manager to unsubscribe on exit.

Return type:

Handle