From 6138cd39d3e505741c3f8ccab57f6934a7cfe72d Mon Sep 17 00:00:00 2001
From: Bert Palm <bert.palm@ufz.de>
Date: Wed, 12 Feb 2020 18:16:37 +0100
Subject: [PATCH] WIP - improve itype 2.0

---
 dios/itypes.py | 92 ++++++++++++++++++++++++++++----------------------
 1 file changed, 51 insertions(+), 41 deletions(-)

diff --git a/dios/itypes.py b/dios/itypes.py
index edc44d5..e31bd3a 100644
--- a/dios/itypes.py
+++ b/dios/itypes.py
@@ -8,92 +8,102 @@ class __Itype:
 
 class DatetimeItype(__Itype):
     name = 'datetime'
+    unique = True
     subtypes = (pd.DatetimeIndex,)
 
 
 class IntegerItype(__Itype):
     name = 'integer'
+    unique = True
     subtypes = (pd.RangeIndex, pd.Int64Index, pd.UInt64Index,)
 
 
 class FloatItype(__Itype):
     name = 'float'
     subtypes = (pd.Float64Index,)
-
-
-class NumericItype(__Itype):
-    name = "numeric"
-    subtypes = (pd.RangeIndex, pd.Int64Index, pd.UInt64Index, pd.Float64Index,)
+    unique = True
 
 
 class OtherItype(__Itype):
     name = "other"
     subtypes = (pd.CategoricalIndex, pd.IntervalIndex, pd.PeriodIndex,)
+    unique = True
 
 
 # class MultiItype(__Itype):
 #     name = "multi"
 #     subtypes = (pd.MultiIndex, )
+#     unique = ??
+
+
+class NumericItype(__Itype):
+    name = "numeric"
+    subtypes = (IntegerItype.subtypes + FloatItype.subtypes)
+    unique = False
 
 
 class MixedItype (__Itype):
     name = "mixed"
-    subtypes = (pd.DatetimeIndex, pd.RangeIndex, pd.Int64Index, pd.UInt64Index, pd.RangeIndex,
-                pd.CategoricalIndex, pd.IntervalIndex, pd.PeriodIndex,
+    unique = False
+    subtypes = (DatetimeItype.subtypes +
+                NumericItype.subtypes +
+                OtherItype.subtypes +
                 # pd.MultiIndex, not supported
-                )
-
+                ())
 
-__itypedict = {
-    DatetimeItype.name: DatetimeItype,
-    IntegerItype.name: IntegerItype,
-    FloatItype.name: FloatItype,
-    NumericItype.name: NumericItype,
-    OtherItype.name: OtherItype,
-    MixedItype.name: MixedItype,
-}
 
-
-def __is_itype_like(itype, obj):
-    """ Check if obj is a subclass or a instance of the given itype or any of its subtypes"""
-    # user gave a string, like 'datetime'
-    if isinstance(obj, str) and obj == itype.name:
-        return True
+def is_itype(obj, itype):
+    """ Check if obj is a instance of the given itype or its str-alias was given"""
     # user gave a Itype, like ``DatetimeItype``
     if issubclass(obj, itype):
         return True
+    # user gave a string, like 'datetime'
+    if isinstance(obj, str) and obj == itype.name:
+        return True
+    return False
 
-    # check subtypes
 
-    # user gave a instance of a subtype, like ``pd.Series(..).index``
-    if isinstance(obj, itype.subtypes):
-        return True
+def is_itype_subtype(obj, itype):
+    """ Check if obj is a subclass or a instance of a subclass of the given itype"""
     # user gave a subtype, like ``pd.DatetimeIndex``
     if issubclass(obj, itype.subtypes):
         return True
-
+    # user gave a instance of a subtype, like ``pd.Series(..).index``
+    if isinstance(obj, itype.subtypes):
+        return True
     return False
 
 
+def is_itype_like(obj, itype):
+    """ Check if obj is a subclass or a instance of the given itype or any of its subtypes"""
+    return is_itype(obj, itype) or is_itype_subtype(obj, itype)
+
+
 def get_itype(obj):
     """
-    handle any possible user input, like
+    Return the according Itype, by any of any possible user input, like
       - "datetime"
       - DatetimeItype
       - pd.Series(...).index
       - pd.DatetimeIndex
     and return the according Itype
     """
-    t = DatetimeItype
-    if __is_itype_like(t):
-        return t
-
-    t = NumericItype
-    if __is_itype_like(t):
-        numtypes = [IntegerItype, FloatItype, MixedItype]
-        for t in types:
-            if __is_itype_like(t):
-                return t
-        return t
-    raise ValueError(f"{type(obj)} is not a indextype nor any known subtype of pd.Index")
+    # shortcut
+    if issubclass(obj, __Itype):
+        return obj
+
+    # check if it is the actual type, not a subtype
+    types = [DatetimeItype, NumericItype, IntegerItype, FloatItype, OtherItype, MixedItype]
+    for t in types:
+        if is_itype(obj, t):
+            return t
+
+    # If the above failed, we try to infer the itype by its subtypes.
+    # We just check the unique types, because the non-unique are just
+    # collections of unique subtypes.
+    for t in types:
+        if is_itype_subtype(obj, t) and t.unique:
+            return t
+
+    raise ValueError(f"{obj} is not a itype, nor any known subtype of a itype, nor a itype string alias")
 
-- 
GitLab