Source code for networktables.util

from typing import Callable, Optional, Sequence

from . import NetworkTablesInstance

__all__ = ["ntproperty", "ChooserControl"]

NetworkTables = NetworkTablesInstance.getDefault()


class _NtProperty:
    def __init__(
        self,
        key: str,
        defaultValue,
        writeDefault: bool,
        persistent: bool,
        inst: NetworkTablesInstance,
    ) -> None:
        self.key = key
        self.defaultValue = defaultValue
        self.writeDefault = writeDefault
        self.persistent = persistent
        # never overwrite persistent values with defaults
        if persistent:
            self.writeDefault = False
        self.inst = inst
        if hasattr(self.inst, "_api"):
            self.set = self._set_pynetworktables
        else:
            self.set = self._set_pyntcore

        self.reset()

    def reset(self):
        self.ntvalue = self.inst.getGlobalAutoUpdateValue(
            self.key, self.defaultValue, self.writeDefault
        )
        if self.persistent:
            self.ntvalue.setPersistent()

        if hasattr(self.inst, "_api"):
            from _pynetworktables import Value
        else:
            from . import Value

        # this is an optimization, but presumes the value type never changes
        self.mkv = Value.getFactoryByType(self.ntvalue.getType())

    def get(self, _):
        return self.ntvalue.value

    def _set_pynetworktables(self, _, value):
        self.inst._api.setEntryValueById(self.ntvalue._local_id, self.mkv(value))

    def _set_pyntcore(self, _, value):
        self.ntvalue.setValue(self.mkv(value))


[docs]def ntproperty( key: str, defaultValue, writeDefault: bool = True, doc: str = None, persistent: bool = False, *, inst: NetworkTablesInstance = NetworkTables ) -> property: """ A property that you can add to your classes to access NetworkTables variables like a normal variable. :param key: A full NetworkTables key (eg ``/SmartDashboard/foo``) :param defaultValue: Default value to use if not in the table :type defaultValue: any :param writeDefault: If True, put the default value to the table, overwriting existing values :param doc: If given, will be the docstring of the property. :param persistent: If True, persist set values across restarts. *writeDefault* is ignored if this is True. :param inst: The NetworkTables instance to use. Example usage:: class Foo(object): something = ntproperty('/SmartDashboard/something', True) ... def do_thing(self): if self.something: # reads from value ... self.something = False # writes value .. note:: Does not work with empty lists/tuples. Getting the value of this property should be reasonably fast, but setting the value will have just as much overhead as :meth:`.NetworkTable.putValue` .. warning:: This function assumes that the value's type never changes. If it does, you'll get really strange errors... so don't do that. .. versionadded:: 2015.3.0 .. versionchanged:: 2017.0.6 The *doc* parameter. .. versionchanged:: 2018.0.0 The *persistent* parameter. """ ntprop = _NtProperty(key, defaultValue, writeDefault, persistent, inst) try: inst._ntproperties.add(ntprop) except AttributeError: pass # pyntcore compat return property(fget=ntprop.get, fset=ntprop.set, doc=doc)
[docs]class ChooserControl(object): """ Interacts with a :class:`wpilib.SendableChooser` object over NetworkTables. """ def __init__( self, key: str, on_choices: Optional[Callable[[Sequence[str]], None]] = None, on_selected: Optional[Callable[[str], None]] = None, *, inst: NetworkTablesInstance = NetworkTables ) -> None: """ :param key: NetworkTables key :param on_choices: A function that will be called when the choices change. :param on_selection: A function that will be called when the selection changes. :param inst: The NetworkTables instance to use. """ self.subtable = inst.getTable("SmartDashboard").getSubTable(key) self.on_choices = on_choices self.on_selected = on_selected if on_choices or on_selected: self.subtable.addTableListener(self._on_change, True)
[docs] def close(self) -> None: """Stops listening for changes to the ``SendableChooser``""" if self.on_choices or self.on_selected: self.subtable.removeTableListener(self._on_change)
[docs] def getChoices(self) -> Sequence[str]: """ Returns the current choices. If the chooser doesn't exist, this will return an empty tuple. """ return self.subtable.getStringArray("options", ())
[docs] def getSelected(self) -> Optional[str]: """ Returns the current selection or None """ selected = self.subtable.getString("selected", None) if selected is None: selected = self.subtable.getString("default", None) return selected
[docs] def setSelected(self, selection: str) -> None: """ Sets the active selection on the chooser :param selection: Active selection name """ self.subtable.putString("selected", selection)
def _on_change(self, table, key, value, isNew): if key == "options": if self.on_choices is not None: self.on_choices(value) elif key == "selected": if self.on_selected is not None: self.on_selected(value) elif key == "default": if ( self.on_selected is not None and self.subtable.getString("selected", None) is None ): self.on_selected(value)