scripts: Adding initial version of the python-skywater-pdk module.

Signed-off-by: Tim 'mithro' Ansell <tansell@google.com>
diff --git a/scripts/python-skywater-pdk/skywater_pdk/utils.py b/scripts/python-skywater-pdk/skywater_pdk/utils.py
new file mode 100644
index 0000000..d0b284a
--- /dev/null
+++ b/scripts/python-skywater-pdk/skywater_pdk/utils.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020 SkyWater PDK Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import dataclasses
+import dataclasses_json
+import random
+import sys
+
+from dataclasses import dataclass
+from dataclasses_json import dataclass_json
+from enum import Flag
+from typing import Optional, Tuple, Any
+
+
+def dataclass_json_passthru_config(*args, **kw):
+    return dataclasses.field(
+        *args,
+        metadata=dataclasses_json.config(
+            encoder=lambda x: x.to_json(),
+            #decoder=lambda x: x.from_json(),
+        ),
+        **kw,
+    )
+
+def dataclass_json_passthru_sequence_config(*args, **kw):
+    def to_json_sequence(s):
+        if s is None:
+            return None
+        o = []
+        for i in s:
+            if hasattr(i, 'to_json'):
+                o.append(i.to_json())
+            else:
+                o.append(i)
+        return o
+
+    return dataclasses.field(
+        *args,
+        metadata=dataclasses_json.config(
+            encoder=to_json_sequence,
+            #decoder=lambda x: x.from_json(),
+        ),
+        **kw,
+    )
+
+
+
+def comparable_to_none(cls):
+    """
+
+    >>> @comparable_to_none
+    ... @dataclass(order=True)
+    ... class A:
+    ...     a: int = 0
+    >>> @comparable_to_none
+    ... @dataclass(order=True)
+    ... class B:
+    ...     b: Optional[A] = None
+    >>> b0 = B()
+    >>> repr(b0)
+    'B(b=None)'
+    >>> str(b0)
+    'B(b=None)'
+    >>> b1 = B(A())
+    >>> repr(b1)
+    'B(b=A(a=0))'
+    >>> str(b1)
+    'B(b=A(a=0))'
+    >>> b2 = B(A(2))
+    >>> repr(b2)
+    'B(b=A(a=2))'
+    >>> str(b2)
+    'B(b=A(a=2))'
+    >>> l = [b0, b1, b2, None]
+    >>> for i in range(0, 3):
+    ...     random.shuffle(l)
+    ...     l.sort()
+    ...     print(l)
+    [None, B(b=None), B(b=A(a=0)), B(b=A(a=2))]
+    [None, B(b=None), B(b=A(a=0)), B(b=A(a=2))]
+    [None, B(b=None), B(b=A(a=0)), B(b=A(a=2))]
+
+    """
+    class ComparableToNoneVersion(cls):
+        def __ge__(self, other):
+            if other is None:
+                return True
+            return super().__ge__(other)
+        def __gt__(self, other):
+            if other is None:
+                return True
+            return super().__gt__(other)
+        def __le__(self, other):
+            if other is None:
+                return False
+            return super().__le__(other)
+        def __lt__(self, other):
+            if other is None:
+                return False
+            return super().__lt__(other)
+        def __eq__(self, other):
+            if other is None:
+                return False
+            return super().__eq__(other)
+        def __hash__(self):
+            return super().__hash__()
+        def __repr__(self):
+            s = super().__repr__()
+            return s.replace('comparable_to_none.<locals>.ComparableToNoneVersion', cls.__name__)
+
+    return ComparableToNoneVersion
+
+
+def _is_optional_type(t):
+    """
+    >>> _is_optional_type(Optional[int])
+    True
+    >>> _is_optional_type(Optional[Tuple])
+    True
+    >>> _is_optional_type(Any)
+    False
+    """
+    return hasattr(t, "__args__") and len(t.__args__) == 2 and t.__args__[-1] is type(None)
+
+
+def _get_the_optional_type(t):
+    """
+    >>> _get_the_optional_type(Optional[int])
+    <class 'int'>
+    >>> _get_the_optional_type(Optional[Tuple])
+    typing.Tuple
+    >>> class A:
+    ...     pass
+    >>> _get_the_optional_type(Optional[A])
+    <class '__main__.A'>
+    >>> _get_type_name(_get_the_optional_type(Optional[A]))
+    'A'
+    """
+    assert _is_optional_type(t), t
+    return t.__args__[0]
+
+
+def _get_type_name(ot):
+    """
+    >>> _get_type_name(int)
+    'int'
+    >>> _get_type_name(Tuple)
+    'Tuple'
+    >>> _get_type_name(Optional[Tuple])
+    'typing.Union[typing.Tuple, NoneType]'
+    """
+    if hasattr(ot, "_name") and ot._name:
+        return ot._name
+    elif hasattr(ot, "__name__") and ot.__name__:
+        return ot.__name__
+    else:
+        return str(ot)
+
+
+class OrderedFlag(Flag):
+    def __ge__(self, other):
+        if other is None:
+            return True
+        if self.__class__ is other.__class__:
+            return self.value >= other.value
+        return NotImplemented
+    def __gt__(self, other):
+        if other is None:
+            return True
+        if self.__class__ is other.__class__:
+            return self.value > other.value
+        return NotImplemented
+    def __le__(self, other):
+        if other is None:
+            return False
+        if self.__class__ is other.__class__:
+            return self.value <= other.value
+        return NotImplemented
+    def __lt__(self, other):
+        if other is None:
+            return False
+        if self.__class__ is other.__class__:
+            return self.value < other.value
+        return NotImplemented
+    def __eq__(self, other):
+        if other is None:
+            return False
+        if self.__class__ is other.__class__:
+            return self.value == other.value
+        return NotImplemented
+    def __hash__(self):
+        return hash(self._name_)
+
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()