dtlib: add Type enum

Instead of hard-coding constants, use an IntEnum.

These is still a subclass of 'int', but is both easier to import and
easier to read during debugging.

For example, compare:

>>> Type.BYTES
<Type.BYTES: 1>

with:

>>> TYPE_BYTES
1

However, 'Type.BYTES == 1' is still True, and the enum values
otherwise behave like you would expect.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
diff --git a/scripts/dts/python-devicetree/src/devicetree/dtlib.py b/scripts/dts/python-devicetree/src/devicetree/dtlib.py
index 37f7ade..67c5c98 100644
--- a/scripts/dts/python-devicetree/src/devicetree/dtlib.py
+++ b/scripts/dts/python-devicetree/src/devicetree/dtlib.py
@@ -17,6 +17,7 @@
 """
 
 import collections
+import enum
 import errno
 import os
 import re
@@ -1336,23 +1337,23 @@
 
         Assignment                  | Property.type
         ----------------------------+------------------------
-        foo;                        | dtlib.TYPE_EMPTY
-        foo = [];                   | dtlib.TYPE_BYTES
-        foo = [01 02];              | dtlib.TYPE_BYTES
-        foo = /bits/ 8 <1>;         | dtlib.TYPE_BYTES
-        foo = <1>;                  | dtlib.TYPE_NUM
-        foo = <>;                   | dtlib.TYPE_NUMS
-        foo = <1 2 3>;              | dtlib.TYPE_NUMS
-        foo = <1 2>, <3>;           | dtlib.TYPE_NUMS
-        foo = "foo";                | dtlib.TYPE_STRING
-        foo = "foo", "bar";         | dtlib.TYPE_STRINGS
-        foo = <&l>;                 | dtlib.TYPE_PHANDLE
-        foo = <&l1 &l2 &l3>;        | dtlib.TYPE_PHANDLES
-        foo = <&l1 &l2>, <&l3>;     | dtlib.TYPE_PHANDLES
-        foo = <&l1 1 2 &l2 3 4>;    | dtlib.TYPE_PHANDLES_AND_NUMS
-        foo = <&l1 1 2>, <&l2 3 4>; | dtlib.TYPE_PHANDLES_AND_NUMS
-        foo = &l;                   | dtlib.TYPE_PATH
-        *Anything else*             | dtlib.TYPE_COMPOUND
+        foo;                        | dtlib.Type.EMPTY
+        foo = [];                   | dtlib.Type.BYTES
+        foo = [01 02];              | dtlib.Type.BYTES
+        foo = /bits/ 8 <1>;         | dtlib.Type.BYTES
+        foo = <1>;                  | dtlib.Type.NUM
+        foo = <>;                   | dtlib.Type.NUMS
+        foo = <1 2 3>;              | dtlib.Type.NUMS
+        foo = <1 2>, <3>;           | dtlib.Type.NUMS
+        foo = "foo";                | dtlib.Type.STRING
+        foo = "foo", "bar";         | dtlib.Type.STRINGS
+        foo = <&l>;                 | dtlib.Type.PHANDLE
+        foo = <&l1 &l2 &l3>;        | dtlib.Type.PHANDLES
+        foo = <&l1 &l2>, <&l3>;     | dtlib.Type.PHANDLES
+        foo = <&l1 1 2 &l2 3 4>;    | dtlib.Type.PHANDLES_AND_NUMS
+        foo = <&l1 1 2>, <&l2 3 4>; | dtlib.Type.PHANDLES_AND_NUMS
+        foo = &l;                   | dtlib.Type.PATH
+        *Anything else*             | dtlib.Type.COMPOUND
 
       *Anything else* includes properties mixing phandle (<&label>) and node
       path (&label) references with other data.
@@ -1404,7 +1405,7 @@
         Returns the value of the property as a number.
 
         Raises DTError if the property was not assigned with this syntax (has
-        Property.type TYPE_NUM):
+        Property.type Type.NUM):
 
             foo = < 1 >;
 
@@ -1412,7 +1413,7 @@
           If True, the value will be interpreted as signed rather than
           unsigned.
         """
-        if self.type is not TYPE_NUM:
+        if self.type is not Type.NUM:
             _err("expected property '{0}' on {1} in {2} to be assigned with "
                  "'{0} = < (number) >;', not '{3}'"
                  .format(self.name, self.node.path, self.node.dt.filename,
@@ -1425,7 +1426,7 @@
         Returns the value of the property as a list of numbers.
 
         Raises DTError if the property was not assigned with this syntax (has
-        Property.type TYPE_NUM or TYPE_NUMS):
+        Property.type Type.NUM or Type.NUMS):
 
             foo = < 1 2 ... >;
 
@@ -1433,7 +1434,7 @@
           If True, the values will be interpreted as signed rather than
           unsigned.
         """
-        if self.type not in (TYPE_NUM, TYPE_NUMS):
+        if self.type not in (Type.NUM, Type.NUMS):
             _err("expected property '{0}' on {1} in {2} to be assigned with "
                  "'{0} = < (number) (number) ... >;', not '{3}'"
                  .format(self.name, self.node.path, self.node.dt.filename,
@@ -1448,11 +1449,11 @@
         Property.value, except with added type checking.
 
         Raises DTError if the property was not assigned with this syntax (has
-        Property.type TYPE_BYTES):
+        Property.type Type.BYTES):
 
             foo = [ 01 ... ];
         """
-        if self.type is not TYPE_BYTES:
+        if self.type is not Type.BYTES:
             _err("expected property '{0}' on {1} in {2} to be assigned with "
                  "'{0} = [ (byte) (byte) ... ];', not '{3}'"
                  .format(self.name, self.node.path, self.node.dt.filename,
@@ -1465,14 +1466,14 @@
         Returns the value of the property as a string.
 
         Raises DTError if the property was not assigned with this syntax (has
-        Property.type TYPE_STRING):
+        Property.type Type.STRING):
 
             foo = "string";
 
         This function might also raise UnicodeDecodeError if the string is
         not valid UTF-8.
         """
-        if self.type is not TYPE_STRING:
+        if self.type is not Type.STRING:
             _err("expected property '{0}' on {1} in {2} to be assigned with "
                  "'{0} = \"string\";', not '{3}'"
                  .format(self.name, self.node.path, self.node.dt.filename,
@@ -1490,13 +1491,13 @@
         Returns the value of the property as a list of strings.
 
         Raises DTError if the property was not assigned with this syntax (has
-        Property.type TYPE_STRING or TYPE_STRINGS):
+        Property.type Type.STRING or Type.STRINGS):
 
             foo = "string", "string", ... ;
 
         Also raises DTError if any of the strings are not valid UTF-8.
         """
-        if self.type not in (TYPE_STRING, TYPE_STRINGS):
+        if self.type not in (Type.STRING, Type.STRINGS):
             _err("expected property '{0}' on {1} in {2} to be assigned with "
                  "'{0} = \"string\", \"string\", ... ;', not '{3}'"
                  .format(self.name, self.node.path, self.node.dt.filename,
@@ -1514,11 +1515,11 @@
         Returns the Node the phandle in the property points to.
 
         Raises DTError if the property was not assigned with this syntax (has
-        Property.type TYPE_PHANDLE).
+        Property.type Type.PHANDLE).
 
             foo = < &bar >;
         """
-        if self.type is not TYPE_PHANDLE:
+        if self.type is not Type.PHANDLE:
             _err("expected property '{0}' on {1} in {2} to be assigned with "
                  "'{0} = < &foo >;', not '{3}'"
                  .format(self.name, self.node.path, self.node.dt.filename,
@@ -1539,10 +1540,10 @@
             foo = < &bar ... >, < &baz ... >;
         """
         def type_ok():
-            if self.type in (TYPE_PHANDLE, TYPE_PHANDLES):
+            if self.type in (Type.PHANDLE, Type.PHANDLES):
                 return True
             # Also accept 'foo = < >;'
-            return self.type is TYPE_NUMS and not self.value
+            return self.type is Type.NUMS and not self.value
 
         if not type_ok():
             _err("expected property '{0}' on {1} in {2} to be assigned with "
@@ -1559,14 +1560,14 @@
         Returns the Node referenced by the path stored in the property.
 
         Raises DTError if the property was not assigned with either of these
-        syntaxes (has Property.type TYPE_PATH or TYPE_STRING):
+        syntaxes (has Property.type Type.PATH or Type.STRING):
 
             foo = &bar;
             foo = "/bar";
 
         For the second case, DTError is raised if the path does not exist.
         """
-        if self.type not in (TYPE_PATH, TYPE_STRING):
+        if self.type not in (Type.PATH, Type.STRING):
             _err("expected property '{0}' on {1} in {2} to be assigned with "
                  "either '{0} = &foo' or '{0} = \"/path/to/node\"', not '{3}'"
                  .format(self.name, self.node.path, self.node.dt.filename,
@@ -1597,35 +1598,35 @@
                  if marker[1] != _REF_LABEL]
 
         if not types:
-            return TYPE_EMPTY
+            return Type.EMPTY
 
         if types == [_TYPE_UINT8]:
-            return TYPE_BYTES
+            return Type.BYTES
 
         if types == [_TYPE_UINT32]:
-            return TYPE_NUM if len(self.value) == 4 else TYPE_NUMS
+            return Type.NUM if len(self.value) == 4 else Type.NUMS
 
-        # Treat 'foo = <1 2 3>, <4 5>, ...' as TYPE_NUMS too
+        # Treat 'foo = <1 2 3>, <4 5>, ...' as Type.NUMS too
         if set(types) == {_TYPE_UINT32}:
-            return TYPE_NUMS
+            return Type.NUMS
 
         if set(types) == {_TYPE_STRING}:
-            return TYPE_STRING if len(types) == 1 else TYPE_STRINGS
+            return Type.STRING if len(types) == 1 else Type.STRINGS
 
         if types == [_REF_PATH]:
-            return TYPE_PATH
+            return Type.PATH
 
         if types == [_TYPE_UINT32, _REF_PHANDLE] and len(self.value) == 4:
-            return TYPE_PHANDLE
+            return Type.PHANDLE
 
         if set(types) == {_TYPE_UINT32, _REF_PHANDLE}:
             if len(self.value) == 4*types.count(_REF_PHANDLE):
                 # Array with just phandles in it
-                return TYPE_PHANDLES
+                return Type.PHANDLES
             # Array with both phandles and numbers
-            return TYPE_PHANDLES_AND_NUMS
+            return Type.PHANDLES_AND_NUMS
 
-        return TYPE_COMPOUND
+        return Type.COMPOUND
 
     def __str__(self):
         s = "".join(label + ": " for label in self.labels) + self.name
@@ -1761,17 +1762,18 @@
 #
 
 # See Property.type
-TYPE_EMPTY = 0
-TYPE_BYTES = 1
-TYPE_NUM = 2
-TYPE_NUMS = 3
-TYPE_STRING = 4
-TYPE_STRINGS = 5
-TYPE_PATH = 6
-TYPE_PHANDLE = 7
-TYPE_PHANDLES = 8
-TYPE_PHANDLES_AND_NUMS = 9
-TYPE_COMPOUND = 10
+class Type(enum.IntEnum):
+    EMPTY = 0
+    BYTES = 1
+    NUM = 2
+    NUMS = 3
+    STRING = 4
+    STRINGS = 5
+    PATH = 6
+    PHANDLE = 7
+    PHANDLES = 8
+    PHANDLES_AND_NUMS = 9
+    COMPOUND = 10
 
 
 def _check_is_bytes(data):
diff --git a/scripts/dts/python-devicetree/src/devicetree/edtlib.py b/scripts/dts/python-devicetree/src/devicetree/edtlib.py
index fe70c99..a9785d3 100644
--- a/scripts/dts/python-devicetree/src/devicetree/edtlib.py
+++ b/scripts/dts/python-devicetree/src/devicetree/edtlib.py
@@ -81,10 +81,7 @@
 except ImportError:
     from yaml import Loader
 
-from devicetree.dtlib import \
-    DT, DTError, to_num, to_nums, TYPE_EMPTY, TYPE_BYTES, \
-    TYPE_NUM, TYPE_NUMS, TYPE_STRING, TYPE_STRINGS, \
-    TYPE_PHANDLE, TYPE_PHANDLES, TYPE_PHANDLES_AND_NUMS
+from devicetree.dtlib import DT, DTError, to_num, to_nums, Type
 from devicetree.grutils import Graph
 
 
@@ -823,26 +820,27 @@
         }
         for name, prop in self._node.props.items():
             pp = OrderedDict()
-            if prop.type == TYPE_EMPTY:
+            if prop.type == Type.EMPTY:
                 pp["type"] = "boolean"
-            elif prop.type == TYPE_BYTES:
+            elif prop.type == Type.BYTES:
                 pp["type"] = "uint8-array"
-            elif prop.type == TYPE_NUM:
+            elif prop.type == Type.NUM:
                 pp["type"] = "int"
-            elif prop.type == TYPE_NUMS:
+            elif prop.type == Type.NUMS:
                 pp["type"] = "array"
-            elif prop.type == TYPE_STRING:
+            elif prop.type == Type.STRING:
                 pp["type"] = "string"
-            elif prop.type == TYPE_STRINGS:
+            elif prop.type == Type.STRINGS:
                 pp["type"] = "string-array"
-            elif prop.type == TYPE_PHANDLE:
+            elif prop.type == Type.PHANDLE:
                 pp["type"] = "phandle"
-            elif prop.type == TYPE_PHANDLES:
+            elif prop.type == Type.PHANDLES:
                 pp["type"] = "phandles"
-            elif prop.type == TYPE_PHANDLES_AND_NUMS:
+            elif prop.type == Type.PHANDLES_AND_NUMS:
                 pp["type"] = "phandle-array"
             else:
-                _err(f"cannot infer binding from property: {prop}")
+                _err(f"cannot infer binding from property: {prop} "
+                     f"with type {prop.type}")
             raw['properties'][name] = pp
 
         # Set up Node state.
@@ -1007,7 +1005,7 @@
             return False if prop_type == "boolean" else None
 
         if prop_type == "boolean":
-            if prop.type is not TYPE_EMPTY:
+            if prop.type is not Type.EMPTY:
                 _err("'{0}' in {1!r} is defined with 'type: boolean' in {2}, "
                      "but is assigned a value ('{3}') instead of being empty "
                      "('{0};')".format(name, node, self.binding_path, prop))
@@ -1038,7 +1036,7 @@
             # This type is a bit high-level for dtlib as it involves
             # information from bindings and *-names properties, so there's no
             # to_phandle_array() in dtlib. Do the type check ourselves.
-            if prop.type not in (TYPE_PHANDLE, TYPE_PHANDLES, TYPE_PHANDLES_AND_NUMS):
+            if prop.type not in (Type.PHANDLE, Type.PHANDLES, Type.PHANDLES_AND_NUMS):
                 _err(f"expected property '{name}' in {node.path} in "
                      f"{node.dt.filename} to be assigned "
                      f"with '{name} = < &foo ... &bar 1 ... &baz 2 3 >' "
@@ -2655,7 +2653,7 @@
 
         ranges_prop = node.props.get("ranges")
         if ranges_prop:
-            if ranges_prop.type not in (TYPE_EMPTY, TYPE_NUMS):
+            if ranges_prop.type not in (Type.EMPTY, Type.NUMS):
                 _err("expected 'ranges = < ... >;' in {} in {}, not '{}' "
                      "(see the devicetree specification)"
                      .format(node.path, node.dt.filename, ranges_prop))
diff --git a/scripts/dts/python-devicetree/tests/test_dtlib.py b/scripts/dts/python-devicetree/tests/test_dtlib.py
index ef8d2b2..1659555 100644
--- a/scripts/dts/python-devicetree/tests/test_dtlib.py
+++ b/scripts/dts/python-devicetree/tests/test_dtlib.py
@@ -1538,30 +1538,30 @@
 };
 """)
 
-    verify_type("empty", dtlib.TYPE_EMPTY)
-    verify_type("bytes1", dtlib.TYPE_BYTES)
-    verify_type("bytes2", dtlib.TYPE_BYTES)
-    verify_type("bytes3", dtlib.TYPE_BYTES)
-    verify_type("bytes4", dtlib.TYPE_BYTES)
-    verify_type("bytes5", dtlib.TYPE_BYTES)
-    verify_type("num", dtlib.TYPE_NUM)
-    verify_type("nums1", dtlib.TYPE_NUMS)
-    verify_type("nums2", dtlib.TYPE_NUMS)
-    verify_type("nums3", dtlib.TYPE_NUMS)
-    verify_type("nums4", dtlib.TYPE_NUMS)
-    verify_type("string", dtlib.TYPE_STRING)
-    verify_type("strings", dtlib.TYPE_STRINGS)
-    verify_type("phandle1", dtlib.TYPE_PHANDLE)
-    verify_type("phandle2", dtlib.TYPE_PHANDLE)
-    verify_type("phandles1", dtlib.TYPE_PHANDLES)
-    verify_type("phandles2", dtlib.TYPE_PHANDLES)
-    verify_type("phandle-and-nums-1", dtlib.TYPE_PHANDLES_AND_NUMS)
-    verify_type("phandle-and-nums-2", dtlib.TYPE_PHANDLES_AND_NUMS)
-    verify_type("phandle-and-nums-3", dtlib.TYPE_PHANDLES_AND_NUMS)
-    verify_type("path1", dtlib.TYPE_PATH)
-    verify_type("path2", dtlib.TYPE_PATH)
-    verify_type("compound1", dtlib.TYPE_COMPOUND)
-    verify_type("compound2", dtlib.TYPE_COMPOUND)
+    verify_type("empty", dtlib.Type.EMPTY)
+    verify_type("bytes1", dtlib.Type.BYTES)
+    verify_type("bytes2", dtlib.Type.BYTES)
+    verify_type("bytes3", dtlib.Type.BYTES)
+    verify_type("bytes4", dtlib.Type.BYTES)
+    verify_type("bytes5", dtlib.Type.BYTES)
+    verify_type("num", dtlib.Type.NUM)
+    verify_type("nums1", dtlib.Type.NUMS)
+    verify_type("nums2", dtlib.Type.NUMS)
+    verify_type("nums3", dtlib.Type.NUMS)
+    verify_type("nums4", dtlib.Type.NUMS)
+    verify_type("string", dtlib.Type.STRING)
+    verify_type("strings", dtlib.Type.STRINGS)
+    verify_type("phandle1", dtlib.Type.PHANDLE)
+    verify_type("phandle2", dtlib.Type.PHANDLE)
+    verify_type("phandles1", dtlib.Type.PHANDLES)
+    verify_type("phandles2", dtlib.Type.PHANDLES)
+    verify_type("phandle-and-nums-1", dtlib.Type.PHANDLES_AND_NUMS)
+    verify_type("phandle-and-nums-2", dtlib.Type.PHANDLES_AND_NUMS)
+    verify_type("phandle-and-nums-3", dtlib.Type.PHANDLES_AND_NUMS)
+    verify_type("path1", dtlib.Type.PATH)
+    verify_type("path2", dtlib.Type.PATH)
+    verify_type("compound1", dtlib.Type.COMPOUND)
+    verify_type("compound2", dtlib.Type.COMPOUND)
 
 def test_prop_type_casting():
     '''Test Property.to_{num,nums,string,strings,node}()'''