from typing import Any, Callable, Sequence, TypeVar, Union
from ._impl.constants import (
NT_BOOLEAN,
NT_DOUBLE,
NT_STRING,
NT_RAW,
NT_BOOLEAN_ARRAY,
NT_DOUBLE_ARRAY,
NT_STRING_ARRAY,
NT_PERSISTENT,
)
from ._impl.value import Value
__all__ = ["NetworkTableEntry"]
D = TypeVar("D")
[docs]class NetworkTableEntry:
"""
Holds a value from NetworkTables, and changes it as new entries
come in. Do not create this object directly, use
:func:`.NetworkTablesInstance.getEntry` or :meth:`.NetworkTable.getEntry`
to obtain an instance of this class.
Using NetworkTableEntry objects to access/change NT values is more
efficient than the getX/putX methods of :class:`.NetworkTable`.
.. versionadded:: 2018.0.0
"""
__slots__ = ["__api", "_local_id", "key", "_value"]
def __init__(self, api, local_id, key):
self.__api = api
self._local_id = local_id
self.key = key
self._value = None
[docs] def getHandle(self):
"""Gets the native handle for the entry"""
return self._local_id
[docs] def exists(self) -> bool:
"""Determines if the entry currently exists"""
return self.__api.getEntryTypeById(self._local_id) != 0
[docs] def getName(self) -> str:
"""Gets the name of the entry (the key)"""
return self.key
[docs] def getType(self):
"""Gets the type of the entry
:rtype: :class:`.NetworkTablesInstance.EntryTypes`
"""
return self.__api.getEntryTypeById(self._local_id)
[docs] def getFlags(self) -> int:
"""Returns the flags.
:returns: the flags (bitmask)
"""
return self.__api.getEntryFlagsById(self._local_id)
[docs] def getInfo(self) -> tuple:
"""Gets combined information about the entry.
:returns: Entry information
:rtype: tuple of (name, type, flags)
"""
return self.__api.getEntryInfoById(self._local_id)
@property
def value(self):
"""Property to access the value of this entry, or None if the entry
hasn't been initialized yet (use setXXX or forceXXX)
"""
try:
return self._value[1]
except TypeError:
return None
# deprecated, from autoUpdateValue
[docs] def get(self):
try:
return self._value[1]
except TypeError:
return None
[docs] def getBoolean(self, defaultValue: D) -> Union[bool, D]:
"""Gets the entry's value as a boolean. If the entry does not exist or is of
different type, it will return the default value.
:param defaultValue: the value to be returned if no value is found
:returns: the entry's value or the given default value
"""
value = self._value
if not value or value[0] != NT_BOOLEAN:
return defaultValue
return value[1]
[docs] def getDouble(self, defaultValue: D) -> Union[float, D]:
"""Gets the entry's value as a double. If the entry does not exist or is of
different type, it will return the default value.
:param defaultValue: the value to be returned if no value is found
:returns: the entry's value or the given default value
"""
value = self._value
if not value or value[0] != NT_DOUBLE:
return defaultValue
return value[1]
getNumber = getDouble
[docs] def getString(self, defaultValue: D) -> Union[str, D]:
"""Gets the entry's value as a string. If the entry does not exist or is of
different type, it will return the default value.
:param defaultValue: the value to be returned if no value is found
:returns: the entry's value or the given default value
"""
value = self._value
if not value or value[0] != NT_STRING:
return defaultValue
return value[1]
[docs] def getRaw(self, defaultValue: D) -> Union[bytes, D]:
"""Gets the entry's value as a raw value (byte array). If the entry does not
exist or is of different type, it will return the default value.
:param defaultValue: the value to be returned if no value is found
:returns: the entry's value or the given default value
"""
value = self._value
if not value or value[0] != NT_RAW:
return defaultValue
return value[1]
[docs] def getBooleanArray(self, defaultValue: D) -> Union[Sequence[bool], D]:
"""Gets the entry's value as a boolean array. If the entry does not
exist or is of different type, it will return the default value.
:param defaultValue: the value to be returned if no value is found
:returns: the entry's value or the given default value
"""
value = self._value
if not value or value[0] != NT_BOOLEAN_ARRAY:
return defaultValue
return value[1]
[docs] def getDoubleArray(self, defaultValue: D) -> Union[Sequence[float], D]:
"""Gets the entry's value as a double array. If the entry does not
exist or is of different type, it will return the default value.
:param defaultValue: the value to be returned if no value is found
:returns: the entry's value or the given default value
"""
value = self._value
if not value or value[0] != NT_DOUBLE_ARRAY:
return defaultValue
return value[1]
[docs] def getStringArray(self, defaultValue: D) -> Union[Sequence[str], D]:
"""Gets the entry's value as a string array. If the entry does not
exist or is of different type, it will return the default value.
:param defaultValue: the value to be returned if no value is found
:returns: the entry's value or the given default value
:rtype: list(float)
"""
value = self._value
if not value or value[0] != NT_STRING_ARRAY:
return defaultValue
return value[1]
[docs] @classmethod
def isValidDataType(cls, data):
if isinstance(data, (bytes, bytearray)):
return True
if isinstance(data, (list, tuple)):
if len(data) == 0:
raise ValueError("If you use a list here, cannot be empty")
data = data[0]
return isinstance(data, (int, float, str, bool))
[docs] def setDefaultValue(self, defaultValue) -> bool:
"""Sets the entry's value if it does not exist.
:param defaultValue: the default value to set
:returns: False if the entry exists with a different type
.. warning:: Do not set an empty list, it will fail
"""
value = Value.getFactory(defaultValue)(defaultValue)
return self.__api.setDefaultEntryValueById(self._local_id, value)
[docs] def setDefaultBoolean(self, defaultValue: bool) -> bool:
"""Sets the entry's value if it does not exist.
:param defaultValue: the default value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeBoolean(defaultValue)
return self.__api.setDefaultEntryValueById(self._local_id, value)
[docs] def setDefaultDouble(self, defaultValue: float) -> bool:
"""Sets the entry's value if it does not exist.
:param defaultValue: the default value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeDouble(defaultValue)
return self.__api.setDefaultEntryValueById(self._local_id, value)
setDefaultNumber = setDefaultDouble
[docs] def setDefaultString(self, defaultValue: str) -> bool:
"""Sets the entry's value if it does not exist.
:param defaultValue: the default value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeString(defaultValue)
return self.__api.setDefaultEntryValueById(self._local_id, value)
[docs] def setDefaultRaw(self, defaultValue: bytes) -> bool:
"""Sets the entry's value if it does not exist.
:param defaultValue: the default value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeRaw(defaultValue)
return self.__api.setDefaultEntryValueById(self._local_id, value)
[docs] def setDefaultBooleanArray(self, defaultValue: Sequence[bool]) -> bool:
"""Sets the entry's value if it does not exist.
:param defaultValue: the default value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeBooleanArray(defaultValue)
return self.__api.setDefaultEntryValueById(self._local_id, value)
[docs] def setDefaultDoubleArray(self, defaultValue: Sequence[float]) -> bool:
"""Sets the entry's value if it does not exist.
:param defaultValue: the default value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeDoubleArray(defaultValue)
return self.__api.setDefaultEntryValueById(self._local_id, value)
setDefaultNumberArray = setDefaultDoubleArray
[docs] def setDefaultStringArray(self, defaultValue: Sequence[str]) -> bool:
"""Sets the entry's value if it does not exist.
:param defaultValue: the default value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeStringArray(defaultValue)
return self.__api.setDefaultEntryValueById(self._local_id, value)
[docs] def setValue(self, value) -> bool:
"""Sets the entry's value
:param value: the value that will be assigned
:returns: False if the table key already exists with a different type
.. warning:: Empty lists will fail
"""
value = Value.getFactory(value)(value)
return self.__api.setEntryValueById(self._local_id, value)
[docs] def setBoolean(self, value: bool) -> bool:
"""Sets the entry's value.
:param value: the value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeBoolean(value)
return self.__api.setEntryValueById(self._local_id, value)
[docs] def setDouble(self, value: float) -> bool:
"""Sets the entry's value.
:param value: the value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeDouble(value)
return self.__api.setEntryValueById(self._local_id, value)
setNumber = setDouble
[docs] def setString(self, value: str) -> bool:
"""Sets the entry's value.
:param value: the value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeString(value)
return self.__api.setEntryValueById(self._local_id, value)
[docs] def setRaw(self, value: bytes) -> bool:
"""Sets the entry's value.
:param value: the value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeRaw(value)
return self.__api.setEntryValueById(self._local_id, value)
[docs] def setBooleanArray(self, value: Sequence[bool]) -> bool:
"""Sets the entry's value.
:param value: the value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeBooleanArray(value)
return self.__api.setEntryValueById(self._local_id, value)
[docs] def setDoubleArray(self, value: Sequence[float]) -> bool:
"""Sets the entry's value.
:param value: the value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeDoubleArray(value)
return self.__api.setEntryValueById(self._local_id, value)
setNumberArray = setDoubleArray
[docs] def setStringArray(self, value: Sequence[str]) -> bool:
"""Sets the entry's value.
:param value: the value to set
:returns: False if the entry exists with a different type
"""
value = Value.makeStringArray(value)
return self.__api.setEntryValueById(self._local_id, value)
[docs] def forceSetValue(self, value):
"""Sets the entry's value
:param value: the value that will be assigned
.. warning:: Empty lists will fail
"""
value = Value.getFactory(value)(value)
return self.__api.setEntryTypeValueById(self._local_id, value)
[docs] def forceSetBoolean(self, value: bool):
"""Sets the entry's value.
:param value: the value to set
"""
value = Value.makeBoolean(value)
return self.__api.setEntryTypeValueById(self._local_id, value)
[docs] def forceSetDouble(self, value: float):
"""Sets the entry's value.
:param value: the value to set
"""
value = Value.makeDouble(value)
return self.__api.setEntryTypeValueById(self._local_id, value)
forceSetNumber = forceSetDouble
[docs] def forceSetString(self, value: str):
"""Sets the entry's value.
:param value: the value to set
"""
value = Value.makeString(value)
return self.__api.setEntryTypeValueById(self._local_id, value)
[docs] def forceSetRaw(self, value: bytes):
"""Sets the entry's value.
:param value: the value to set
"""
value = Value.makeRaw(value)
return self.__api.setEntryTypeValueById(self._local_id, value)
[docs] def forceSetBooleanArray(self, value: Sequence[bool]):
"""Sets the entry's value.
:param value: the value to set
"""
value = Value.makeBooleanArray(value)
return self.__api.setEntryTypeValueById(self._local_id, value)
[docs] def forceSetDoubleArray(self, value: Sequence[float]):
"""Sets the entry's value.
:param value: the value to set
"""
value = Value.makeDoubleArray(value)
return self.__api.setEntryTypeValueById(self._local_id, value)
forceSetNumberArray = forceSetDoubleArray
[docs] def forceSetStringArray(self, value: Sequence[str]):
"""Sets the entry's value.
:param value: the value to set
"""
value = Value.makeStringArray(value)
return self.__api.setEntryTypeValueById(self._local_id, value)
[docs] def setFlags(self, flags: int) -> None:
"""Sets flags.
:param flags: the flags to set (bitmask)
"""
flags = self.getFlags() | flags
self.__api.setEntryFlagsById(self._local_id, flags)
[docs] def clearFlags(self, flags: int) -> None:
"""Clears flags
:param flags: the flags to clear (bitmask)
"""
flags = self.getFlags() & ~flags
self.__api.setEntryFlagsById(self._local_id, flags)
[docs] def setPersistent(self) -> None:
"""Make value persistent through program restarts."""
self.setFlags(NT_PERSISTENT)
[docs] def clearPersistent(self) -> None:
"""Stop making value persistent through program restarts."""
self.clearFlags(NT_PERSISTENT)
[docs] def isPersistent(self) -> bool:
"""Returns whether the value is persistent through program restarts.
:returns: True if the value is persistent.
"""
return (self.getFlags() & NT_PERSISTENT) != 0
[docs] def delete(self) -> bool:
"""Deletes the entry."""
return self.__api.deleteEntryById(self._local_id)
#
# TODO: RPC entry stuff not implemented
#
[docs] def addListener(
self,
listener: Callable[["NetworkTableEntry", str, Any, int], None],
flags: int,
paramIsNew: bool = True,
):
"""Add a listener for changes to the entry
:param listener: the listener to add
:type listener: `callable(entry, key, value, param)`
:param flags: bitmask specifying desired notifications
:type flags: :class:`.NetworkTablesInstance.NotifyFlags`
:param paramIsNew: If True, the listener fourth parameter is a boolean set to True
if the listener is being called because of a new value in the
table. Otherwise, the parameter is an integer of the raw
`NT_NOTIFY_*` flags
:returns: listener handle
"""
return self.__api.addEntryListenerByIdEx(
self, self.key, self._local_id, listener, flags, paramIsNew
)
[docs] def removeListener(self, listener_id) -> None:
"""Remove a listener from receiving entry events
:param listener: the callable that was passed to addListener
"""
self.__api.removeEntryListener(listener_id)
# Comparison operators et al
def __lt__(self, other):
raise TypeError(
"< not allowed on NetworkTableEntry objects. Use the .value attribute instead"
)
def __le__(self, other):
raise TypeError(
"<= not allowed on NetworkTableEntry objects. Use the .value attribute instead"
)
def __eq__(self, other):
raise TypeError(
"== not allowed on NetworkTableEntry objects. Use the .value attribute instead"
)
def __ne__(self, other):
raise TypeError(
"!= not allowed on NetworkTableEntry objects. Use the .value attribute instead"
)
def __gt__(self, other):
raise TypeError(
"> not allowed on NetworkTableEntry objects. Use the .value attribute instead"
)
def __ge__(self, other):
raise TypeError(
">= not allowed on NetworkTableEntry objects. Use the .value attribute instead"
)
def __bool__(self):
raise TypeError(
"< not allowed on NetworkTableEntry objects. Use the .value attribute instead"
)
def __repr__(self):
return "<NetworkTableEntry: %s>" % (self._value.__repr__(),)