def getGlobalAutoUpdateValue(cls, key, defaultValue, writeDefault): """Global version of getAutoUpdateValue. This function will not initialize NetworkTables. :param key: the full NT path of the value (must start with /) :type key: str :param defaultValue: The default value to return if the key doesn't exist :type defaultValue: any :param writeDefault: If True, force the value to the specified default :type writeDefault: bool .. versionadded:: 2015.3.0 .. seealso:: :func:`.ntproperty` is a read-write alternative to this """ assert key.startswith("/") # Use raw NT api to avoid having to initialize networktables value = None valuefn = None # optimization for ntproperty if not writeDefault: value = cls._api.getEntryValue(key) if value is None: valuefn = Value.getFactory(defaultValue) cls._api.setEntryValue(key, valuefn(defaultValue)) value = defaultValue else: valuefn = Value.getFactory(value) return cls._api.createAutoValue(key, AutoUpdateValue(key, value, valuefn))
def putValue(self, key, value): """Put a value in the table, trying to autodetect the NT type of the value. Refer to this table to determine the type mapping: ======= ============================ ================================= PyType NT Type Notes ======= ============================ ================================= bool :attr:`.EntryTypes.BOOLEAN` int :attr:`.EntryTypes.DOUBLE` float :attr:`.EntryTypes.DOUBLE` str :attr:`.EntryTypes.STRING` bytes :attr:`.EntryTypes.RAW` Doesn't work in Python 2.7 list Error Use `putXXXArray` methods instead tuple Error Use `putXXXArray` methods instead ======= ============================ ================================= :param key: the key to be assigned to :type key: str :param value: the value that will be assigned :type value: bool, int, float, str, bytes :returns: False if the table key already exists with a different type :rtype: bool .. versionadded:: 2017.0.0 """ value = Value.getFactory(value)(value) path = self._path + key return self._api.setEntryValue(path, value)
def set_safe(self, name: str, value: NT_TYPES) -> None: entry = self._get_entry(name) # Calculated using Python type (bool, str, float) try: create_value_func: Callable[..., Value] = Value.getFactory(value) except ValueError as e: # getFactory raises ValueError when it should be raising TypeError raise TypeError(*e.args) if entry is not None: # Calculated using NT type (NT_BOOLEAN, NT_STRING, NT_DOUBLE) if Value.getFactoryByType(entry.type) != create_value_func: # The factories don't match, which means the types don't match # Do not allow implicit type conversion raise TypeError("Existing type {} does not match: {}".format( entry.type, type(value))) # Convert Python type into NT type nt_value: Value = create_value_func(value) # Returns False on error (type mismatch) successful = self.api.setEntryValue(self._get_path(name), nt_value) if not successful: raise TypeError("Existing type {} does not match: {}".format( entry.type, type(value)))
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)
def setValue(self, value): """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)
def setDefaultValue(self, defaultValue): """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)
def set(self, name: str, value: NT_TYPES) -> None: # Calculated using Python type (bool, str, float) try: create_value_func: Callable[..., Value] = Value.getFactory(value) except ValueError as e: # getFactory raises ValueError when it should be raising TypeError raise TypeError(*e.args) nt_value: Value = create_value_func(value) self.api.setEntryTypeValue(self._get_path(name), nt_value)
def getGlobalAutoUpdateValue(cls, key, defaultValue, writeDefault): '''Global version of getAutoUpdateValue. This function will not initialize NetworkTables. :param key: the full NT path of the value (must start with /) :type key: str :param defaultValue: The default value to return if the key doesn't exist :type defaultValue: any :param writeDefault: If True, force the value to the specified default :type writeDefault: bool .. versionadded:: 2015.3.0 .. seealso:: :func:`.ntproperty` is a read-write alternative to this ''' assert key.startswith('/') # Use raw NT api to avoid having to initialize networktables value = None valuefn = None # optimization for ntproperty if not writeDefault: value = cls._api.getEntryValue(key) if value is None: valuefn = Value.getFactory(defaultValue) cls._api.setEntryValue(key, valuefn(defaultValue)) value = defaultValue elif not writeDefault: value = value.value valuefn = Value.getFactory(value) else: valuefn = Value.getFactory(value) return cls._api.createAutoValue(key, AutoUpdateValue(key, value, valuefn))
def setDefaultValue(self, key, defaultValue): """If the key doesn't currently exist, then the specified value will be assigned to the key. :param key: the key to be assigned to :type key: str :param defaultValue: the default value to set if key doesn't exist. :type defaultValue: bool, int, float, str, bytes :returns: False if the table key exists with a different type .. versionadded:: 2017.0.0 .. seealso:: :meth:`.putValue` """ defaultValue = Value.getFactory(defaultValue)(defaultValue) path = self._path + key return self._api.setDefaultEntryValue(path, defaultValue)
def __init__( self, default: V, *, writeDefault: bool = True, subtable: Optional[str] = None, doc=None ) -> None: if doc is not None: warnings.warn("tunable no longer uses the doc argument", stacklevel=2) self._ntdefault = default self._ntsubtable = subtable self._ntwritedefault = writeDefault # self.__doc__ = doc self._mkv = Value.getFactory(default) self._nt = NetworkTables
def tunable(default, *, writeDefault=True, subtable=None, doc=None): """ This allows you to define simple properties that allow you to easily communicate with other programs via NetworkTables. The following example will define a NetworkTable variable at ``/components/my_component/foo``:: class MyRobot(magicbot.MagicRobot): my_component = MyComponent ... from magicbot import tunable class MyComponent: # define the tunable property foo = tunable(True) def execute(self): # set the variable self.foo = True # get the variable foo = self.foo The key of the NetworkTables variable will vary based on what kind of object the decorated method belongs to: * A component: ``/components/COMPONENTNAME/VARNAME`` * An autonomous mode: ``/autonomous/MODENAME/VARNAME`` * Your main robot class: ``/robot/VARNAME`` .. note:: When executing unit tests on objects that create tunables, you will want to use setup_tunables to set the object up. In normal usage, MagicRobot does this for you, so you don't have to do anything special. """ # the way this works is we use a special class to indicate that it # is a tunable, and MagicRobot adds _ntattr and _global_table variables # to the class property # The tricky bit is that you need to do late binding on these, because # the networktables key is not known when the object is created. Instead, # the name of the key is related to the name of the variable name in the # robot class nt = NetworkTables mkv = Value.getFactory(default) def _get(self): return getattr(self, prop._ntattr).value def _set(self, value): v = getattr(self, prop._ntattr) nt._api.setEntryValueById(v._local_id, mkv(value)) prop = _TunableProperty(fget=_get, fset=_set, doc=doc) prop._ntdefault = default prop._ntsubtable = subtable prop._ntwritedefault = writeDefault return prop