from dataclasses import dataclass
from enum import Enum, auto
from typing import Any, Optional
# Mapping of LoggableType enum index to WPILOG/NT4 type strings
_WPILOG_TYPES = [
"raw",
"boolean",
"int64",
"float",
"double",
"string",
"boolean[]",
"int64[]",
"float[]",
"double[]",
"string[]",
]
_NT4_TYPES = [
"raw",
"boolean",
"int",
"float",
"double",
"string",
"boolean[]",
"int[]",
"float[]",
"double[]",
"string[]",
]
[docs]
@dataclass
class LogValue:
"""
Represents a value in the log table, encapsulating its type, a custom type string, and the value itself.
"""
log_type: "LogValue.LoggableType"
custom_type: str
value: Any
unit: Optional[str] = None
def __init__(
self, value: Any, typeStr: str = "", unit: Optional[str] = None
) -> None:
"""
Initializes a LogValue, inferring the loggable type from the value's Python type.
:param value: The value to be logged.
:param typeStr: An optional custom type string.
:raises TypeError: If the value type is not supported.
"""
self.value = value
self.custom_type = typeStr
self.unit = unit
# Type inference - bool must be checked before int since bool is subclass of int
if isinstance(value, bool):
self.log_type = LogValue.LoggableType.Boolean
elif isinstance(value, int):
self.log_type = LogValue.LoggableType.Integer
elif isinstance(value, float):
self.log_type = LogValue.LoggableType.Double
elif isinstance(value, str):
self.log_type = LogValue.LoggableType.String
elif isinstance(value, bytes):
self.log_type = LogValue.LoggableType.Raw
elif isinstance(value, list):
if len(value) == 0:
self.log_type = LogValue.LoggableType.IntegerArray
elif all(isinstance(x, bool) for x in value):
self.log_type = LogValue.LoggableType.BooleanArray
elif all(isinstance(x, int) for x in value):
self.log_type = LogValue.LoggableType.IntegerArray
elif all(isinstance(x, float) for x in value):
self.log_type = LogValue.LoggableType.DoubleArray
elif all(isinstance(x, str) for x in value):
self.log_type = LogValue.LoggableType.StringArray
else:
raise TypeError("Unsupported list type for LogValue")
else:
raise TypeError(f"Unsupported type for LogValue: {type(value)}")
[docs]
@staticmethod
def withType(
log_type: "LogValue.LoggableType",
data: Any,
typeStr: str = "",
unit: Optional[str] = None,
) -> "LogValue":
"""
Creates a LogValue with a specified loggable type.
:param log_type: The `LoggableType` to assign.
:param data: The value.
:param typeStr: An optional custom type string.
:return: A new `LogValue` instance.
"""
val = LogValue(1, typeStr)
val.log_type = log_type
val.value = data
val.unit = unit
return val
[docs]
def getWPILOGType(self) -> str:
"""
Gets the WPILOG type string for this value.
:return: The custom type string if available, otherwise the default WPILOG type.
"""
if self.custom_type != "":
return self.custom_type
return self.log_type.getWPILOGType()
[docs]
def getNT4Type(self) -> str:
"""
Gets the NT4 type string for this value.
:return: The custom type string if available, otherwise the default NT4 type.
"""
if self.custom_type != "":
return self.custom_type
return self.log_type.getNT4Type()
[docs]
class LoggableType(Enum):
"""Enum for the different types of loggable values."""
Raw = auto()
Boolean = auto()
Integer = auto()
Float = auto()
Double = auto()
String = auto()
BooleanArray = auto()
IntegerArray = auto()
FloatArray = auto()
DoubleArray = auto()
StringArray = auto()
[docs]
def getWPILOGType(self) -> str:
"""
Returns the WPILOG type string corresponding to this loggable type.
:return: The WPILOG type string.
"""
return _WPILOG_TYPES[self.value - 1]
[docs]
def getNT4Type(self) -> str:
"""
Returns the NT4 type string corresponding to this loggable type.
:return: The NT4 type string.
"""
return _NT4_TYPES[self.value - 1]
[docs]
@staticmethod
def fromWPILOGType(typeStr: str) -> "LogValue.LoggableType":
"""
Converts a WPILOG type string to a `LoggableType`.
:param typeStr: The WPILOG type string.
:return: The corresponding `LoggableType`, or `Raw` if not found.
"""
if typeStr in _WPILOG_TYPES:
return LogValue.LoggableType(_WPILOG_TYPES.index(typeStr) + 1)
return LogValue.LoggableType.Raw
[docs]
@staticmethod
def fromNT4Type(typeStr: str) -> "LogValue.LoggableType":
"""
Converts an NT4 type string to a `LoggableType`.
:param typeStr: The NT4 type string.
:return: The corresponding `LoggableType`, or `Raw` if not found.
"""
if typeStr in _NT4_TYPES:
return LogValue.LoggableType(_NT4_TYPES.index(typeStr) + 1)
return LogValue.LoggableType.Raw