LocalVariable
LocalVariable is the right choice when the value belongs
to Python logic rather than to a hardware register. It is still a normal
Variable in the tree, so it can participate in GUIs, polling, formatting,
limits, and remote access, but its storage and behavior stay local to the
application.
Typical use cases:
Software state or configuration values
Values produced by helper libraries or external APIs
GUI-facing controls that should update Python-owned state
Operator-visible status derived from software components rather than from memory-mapped hardware
When To Use LocalVariable
Use LocalVariable when the tree should expose a value, but there is no
hardware address that should be read or written for that value.
That makes it the natural companion to RemoteVariable:
RemoteVariableexposes memory-mapped hardware stateLocalVariableexposes software-owned stateLinkVariableexposes a derived view layered on top of other Variables
Examples of good LocalVariable candidates include run-state flags, file
paths, software counters, cached measurements from another library, and tuning
values that are meaningful to the application even though they are not direct
register fields.
What You Usually Set
Most LocalVariable definitions use the shared Variable parameters from
Variable, plus a small set of local-specific ones:
valuefor a directly stored Python-owned value.localGetto fetch the current value from application state.localSetto push a new value into application state.pollIntervalwhen the local value should be refreshed periodically.
For simple access, localGet and localSet are not required. If the
Variable should just store a Python-owned value directly, value=... is
enough on its own.
How Typing Works
For LocalVariable, the value= argument does two jobs:
It provides the initial stored value.
It establishes the Variable’s native Python type.
In the current implementation, BaseVariable records type(value) as the
native type when value is provided. That means the seed value is the main
type anchor for normal LocalVariable usage.
Examples:
value=Falsemakes the Variable behave like a boolean-backed value.value=0makes it integer-backed.value=''makes it string-backed.value=np.array([...])makes it array-backed and also captures the array dtype and shape fortypeStr.
Important implications:
LocalVariabledoes not automatically coerce later writes to match the seed type.A type mismatch currently produces a warning during
set(), not an exception.typeStris display metadata; it does not enforce conversion by itself.
If you define a callback-only LocalVariable with localGet and no
value, the Variable can still work, but PyRogue does not have a seed value
to infer the native type from up front. In that case, providing a sensible
value= is usually the clearest choice unless you intentionally want the
type to be discovered lazily.
For boolean values, there is one extra convenience: when value is a
bool and no explicit enum is supplied, PyRogue automatically creates a
{False: 'False', True: 'True'} enum for display.
Callbacks And Value Ownership
LocalVariable can either hold a value directly or act as a live view over
some other Python object through callbacks.
If you only need direct stored access, skip the callbacks and provide
value=.... Add localGet and localSet only when the Variable should
proxy some other application state or behavior.
The optional callbacks are:
localGetto produce the current value when the Variable is readlocalSetto apply a new value when the Variable is written
In the current implementation, the callback wrappers support keyword arguments matching:
localGet(dev=None, var=None)localSet(value, dev=None, var=None, changed=None)
The callback may accept any subset of those names. In practice, many
LocalVariable instances use simple callables that only take value or
no explicit arguments at all.
This makes LocalVariable useful for two common patterns:
A stored software value that PyRogue owns directly
A thin tree-facing wrapper around application state owned elsewhere
Design guidance:
Keep callbacks deterministic and low-latency
Avoid long blocking operations in
localGetwhen the Variable is polledMake side effects in
localSetexplicit and idempotent when possibleUse
LocalCommandinstead when the interaction is really an action rather than a persistent value
Examples
Software-Owned State
import pyrogue as pr
class MyDevice(pr.Device):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._is_running = False
self.add(pr.LocalVariable(
name='IsRunning',
mode='RW',
value=self._is_running,
localGet=lambda: self._is_running,
localSet=self._set_is_running,
))
def _set_is_running(self, value):
self._is_running = bool(value)
In this pattern, the tree shows one stable Variable interface while the
actual value is still owned by Python application state.
String-Backed Application Setting
This is a common pattern for software configuration such as file paths, hostnames, or operator-entered labels.
import pyrogue as pr
class FileWriter(pr.Device):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add(pr.LocalVariable(
name='OutputPath',
mode='RW',
value='',
description='Destination path for captured data',
))
Here, value='' makes the Variable string-backed from the start.
Polled Status From A Helper Library
This pattern is common in PyRogue applications: a local counter or status
value is exposed read-only, refreshed by localGet, and polled on an
interval.
import pyrogue as pr
class Stats(pr.Device):
def __init__(self, helper, **kwargs):
super().__init__(**kwargs)
self._helper = helper
self.add(pr.LocalVariable(
name='FrameCount',
mode='RO',
value=0,
typeStr='UInt64',
pollInterval=1,
localGet=self._helper.get_frame_count,
))
The value=0 seed makes the Variable integer-backed, while typeStr lets
the tree present a more specific label to users.
Read-Write Wrapper Over External Application State
This is the pattern to use when the tree should expose a live control surface for an object owned by another Python library.
import pyrogue as pr
class Processor(pr.Device):
def __init__(self, engine, **kwargs):
super().__init__(**kwargs)
self._engine = engine
self.add(pr.LocalVariable(
name='Disable',
mode='RW',
value=False,
localSet=lambda value: self._engine.set_disable(value),
localGet=self._engine.get_disable,
))
This is also a common real-world pattern: the Variable gives GUIs and scripts a normal tree-facing boolean while the actual state lives in another software object.
What To Explore Next
Hardware-backed Variables: RemoteVariable
Linked Variables: LinkVariable
General Variable behavior: Variable
API Reference
See LocalVariable for generated API details.