3 Routines for handling enums (or other symbolic names)
4 Copyright 2015 Cray Inc. All Rights Reserved
10 """Two-way translation between int values (enums, #defines) and strings.
11 Also provides access to value by e.g.:
12 vms = NameSet() # vmstat nameset
13 vms.AddName("NR_FILE_MAPPED", 8)
14 vms.NR_FILE_MAPPED == 8
16 The advantages over just using a dict include:
18 * Define the values once, and get value->string, string->value,
19 and python identifier ns.<name> as above.
20 * The auto-incrementing _next_value
23 def __init__(self, mapping=None):
24 """Create and initialize a NameSet object
27 mapping: if specified, provides a mapping object, e.g. dict,
28 that supplies the initial key(name)/value pairs.
30 self.value_to_name = {}
31 self.name_to_value = {}
34 # self._sorted_values = []
35 # self._sorted_names = []
37 if mapping is not None:
40 def addName(self, name, value=None):
41 """Add a single name, by default using the next value.
43 If two names end up with the same value, the value will map
44 only to the first of them.
47 if name in self.name_to_value.keys():
48 raise ValueError("Name {0} already defined (value {1})".format(
49 name, self.name_to_value[name]))
52 except AttributeError:
55 raise ValueError("Value {0} already used by NameSet object!".
59 value = self._next_value
60 self._next_value = value + 1
62 self.name_to_value[name] = value
63 if value not in self.value_to_name:
64 self.value_to_name[value] = name
65 # self._sorted_values = []
66 # self._sorted_names = []
68 setattr(self, name, value)
70 def addNames(self, *namelist):
71 """Add a list of names, each using the respective next value"""
72 map(self.addName, namelist)
74 def addMap(self, mapping):
75 """Add the key/value pairs from a mapping type"""
76 for k, v in mapping.items():
79 def UFLookup(self, key, **kwargs):
80 return uflookup.UFLookup(self.name_to_value, key, **kwargs)
82 # def somethingUsingSortedArrays:
83 # if not self._sorted_values:
84 # self._sorted_values = sorted(self.value_to_name.keys())
85 # self._sorted_names = sorted(self.name_to_value.keys())
89 if __name__ == '__main__':
92 class Test_NameSet(unittest.TestCase):
93 """Test the NameSet class"""
95 def VerifyName(self, name, value):
96 """Verify that self.ns has name <-> value"""
97 self.assertEqual(value, self.ns.name_to_value[name])
98 self.assertEqual(value, getattr(self.ns, name))
99 self.assertEqual(name, self.ns.value_to_name[value])
101 class Test_Empty(Test_NameSet):
102 """Test an empty NameSet"""
106 def test_empty_vtn(self):
107 self.assertEqual(0, len(self.ns.value_to_name))
108 def test_empty_ntv(self):
109 self.assertEqual(0, len(self.ns.name_to_value))
112 class Test_addName(Test_NameSet):
117 def test_add_one_name(self):
118 self.ns.addName("FOO")
120 self.VerifyName("FOO", 0)
121 self.assertEqual(0, self.ns.FOO)
123 def test_add_two_names(self):
124 self.ns.addName("BAR")
125 self.ns.addName("BAZ")
127 self.VerifyName("BAR", 0)
128 self.VerifyName("BAZ", 1)
129 self.assertEqual(0, self.ns.BAR)
130 self.assertEqual(1, self.ns.BAZ)
133 def test_add_namevalue(self):
134 self.ns.addName("FOO", 87)
135 self.VerifyName("FOO", 87)
136 self.assertEqual(87, self.ns.FOO)
138 def test_reuse_existing_value(self):
139 self.ns.addName("FOO", 2)
140 self.ns.addName("B0",0)
141 self.ns.addName("B1")
142 self.ns.addName("B2")
143 self.ns.addName("B3")
145 self.VerifyName("FOO", 2)
146 self.VerifyName("B0", 0)
147 self.VerifyName("B1", 1)
148 self.assertEqual(2, self.ns.name_to_value["B2"])
149 self.VerifyName("B3", 3)
151 self.assertEqual(2, self.ns.FOO)
152 self.assertEqual(0, self.ns.B0)
153 self.assertEqual(1, self.ns.B1)
154 self.assertEqual(3, self.ns.B3)
156 def test_addNames(self):
157 self.ns.addNames("FOO", "BAR", "BAZ")
158 self.VerifyName("FOO", 0)
159 self.VerifyName("BAR", 1)
160 self.VerifyName("BAZ", 2)
162 self.assertEqual(0, self.ns.FOO)
163 self.assertEqual(1, self.ns.BAR)
164 self.assertEqual(2, self.ns.BAZ)
166 def test_addDupName(self):
167 self.ns.addName("FOO", 1)
168 self.assertRaises(ValueError, self.ns.addName, "FOO", 2)
170 def test_addDupValue(self):
171 self.ns.addName("FOO")
172 self.ns.addName("BAR", 0)
174 self.VerifyName("FOO", 0)
175 self.assertEqual(0, self.ns.name_to_value["BAR"])
177 def test_addMoreDupValues(self):
178 self.ns.addName("FOO")
179 self.ns.addName("BAR", 0)
180 self.ns.addName("BAZ", 0)
182 self.VerifyName("FOO", 0)
183 self.assertEqual(0, self.ns.name_to_value["BAR"])
184 self.assertEqual(0, self.ns.name_to_value["BAZ"])
187 def test_addConflicting(self):
188 self.assertRaises(ValueError, self.ns.addName, "addName")
191 class Test_mapping(Test_NameSet):
192 """Test map handling"""
194 self.ns = NameSet(mapping={"SLEEPY":1, "GRUMPY": 0})
196 def test_constructor(self):
197 self.VerifyName("SLEEPY", 1)
198 self.VerifyName("GRUMPY", 0)
200 def test_addMap(self):
201 self.ns.addMap({"DOC": 9, "BASHFUL": 3})
203 self.VerifyName("SLEEPY", 1)
204 self.VerifyName("GRUMPY", 0)
205 self.VerifyName("DOC", 9)
206 self.VerifyName("BASHFUL", 3)