1
1
import functools
2
2
import inspect
3
+ import warnings
4
+ from typing import Generic , Optional , TypeVar
3
5
4
6
from networktables import NetworkTables
5
7
from ntcore .value import Value
6
8
7
- # Only used as a marker
8
- class _TunableProperty (property ):
9
- pass
9
+ V = TypeVar ("V" )
10
10
11
11
12
- class _AutosendProperty (_TunableProperty ):
13
- pass
14
-
15
-
16
- def tunable (default , * , writeDefault = True , subtable = None , doc = None ):
12
+ class tunable (Generic [V ]):
17
13
"""
18
14
This allows you to define simple properties that allow you to easily
19
15
communicate with other programs via NetworkTables.
@@ -23,18 +19,17 @@ def tunable(default, *, writeDefault=True, subtable=None, doc=None):
23
19
24
20
class MyRobot(magicbot.MagicRobot):
25
21
26
- my_component = MyComponent
22
+ my_component: MyComponent
27
23
28
- ...
24
+ ...
29
25
30
26
from magicbot import tunable
31
27
32
28
class MyComponent:
33
29
34
30
# define the tunable property
35
31
foo = tunable(True)
36
-
37
-
32
+
38
33
def execute(self):
39
34
40
35
# set the variable
@@ -65,33 +60,51 @@ def execute(self):
65
60
# the name of the key is related to the name of the variable name in the
66
61
# robot class
67
62
68
- nt = NetworkTables
69
- mkv = Value .getFactory (default )
70
-
71
- def _get (self ):
72
- return getattr (self , prop ._ntattr ).value
73
-
74
- def _set (self , value ):
75
- v = getattr (self , prop ._ntattr )
76
- nt ._api .setEntryValueById (v ._local_id , mkv (value ))
77
-
78
- prop = _TunableProperty (fget = _get , fset = _set , doc = doc )
79
- prop ._ntdefault = default
80
- prop ._ntsubtable = subtable
81
- prop ._ntwritedefault = writeDefault
82
-
83
- return prop
84
-
85
-
86
- def setup_tunables (component , cname , prefix = "components" ):
63
+ __slots__ = (
64
+ "_ntdefault" ,
65
+ "_ntsubtable" ,
66
+ "_ntwritedefault" ,
67
+ # "__doc__",
68
+ "_mkv" ,
69
+ "_nt" ,
70
+ )
71
+
72
+ def __init__ (
73
+ self ,
74
+ default : V ,
75
+ * ,
76
+ writeDefault : bool = True ,
77
+ subtable : Optional [str ] = None ,
78
+ doc = None
79
+ ) -> None :
80
+ if doc is not None :
81
+ warnings .warn ("tunable no longer uses the doc argument" , stacklevel = 2 )
82
+
83
+ self ._ntdefault = default
84
+ self ._ntsubtable = subtable
85
+ self ._ntwritedefault = writeDefault
86
+ # self.__doc__ = doc
87
+
88
+ self ._mkv = Value .getFactory (default )
89
+ self ._nt = NetworkTables
90
+
91
+ def __get__ (self , instance , owner ) -> V :
92
+ if instance is not None :
93
+ return instance ._tunables [self ].value
94
+ return self
95
+
96
+ def __set__ (self , instance , value ) -> None :
97
+ v = instance ._tunables [self ]
98
+ self ._nt ._api .setEntryValueById (v ._local_id , self ._mkv (value ))
99
+
100
+
101
+ def setup_tunables (component , cname : str , prefix : Optional [str ] = "components" ) -> None :
87
102
"""
88
103
Connects the tunables on an object to NetworkTables.
89
104
90
105
:param component: Component object
91
106
:param cname: Name of component
92
- :type cname: str
93
107
:param prefix: Prefix to use, or no prefix if None
94
- :type prefix: str
95
108
96
109
.. note:: This is not needed in normal use, only useful
97
110
for testing
@@ -104,27 +117,27 @@ def setup_tunables(component, cname, prefix="components"):
104
117
else :
105
118
prefix = "/%s/%s" % (prefix , cname )
106
119
120
+ tunables = {}
121
+
107
122
for n in dir (cls ):
108
123
if n .startswith ("_" ):
109
124
continue
110
125
111
126
prop = getattr (cls , n )
112
- if not isinstance (prop , _TunableProperty ):
127
+ if not isinstance (prop , tunable ):
113
128
continue
114
129
115
130
if prop ._ntsubtable :
116
131
key = "%s/%s/%s" % (prefix , prop ._ntsubtable , n )
117
132
else :
118
133
key = "%s/%s" % (prefix , n )
119
134
120
- ntattr = "_Tunable__%s" % n
121
-
122
135
ntvalue = NetworkTables .getGlobalAutoUpdateValue (
123
136
key , prop ._ntdefault , prop ._ntwritedefault
124
137
)
125
- # double indirection
126
- setattr ( component , ntattr , ntvalue )
127
- prop . _ntattr = ntattr
138
+ tunables [ prop ] = ntvalue
139
+
140
+ component . _tunables = tunables
128
141
129
142
130
143
def feedback (f = None , * , key : str = None ):
0 commit comments