Fokko commented on code in PR #5011:
URL: https://github.com/apache/iceberg/pull/5011#discussion_r901987017


##########
python/src/iceberg/types.py:
##########
@@ -48,107 +57,189 @@ class IcebergType(ABC, Singleton):
         'IcebergType()'
     """
 
-    @property
-    def string_type(self) -> str:
-        return self.__repr__()
-
-    def __str__(self) -> str:
-        return self.string_type
+    @classmethod
+    def __get_validators__(cls):
+        # one or more validators may be yielded which will be called in the
+        # order to validate the input, each validator will receive as an input
+        # the value returned from the previous validator
+        yield cls.validate
+
+    @classmethod
+    def validate(cls, v):
+        # When Pydantic is unable to determine the subtype
+        # In this case we'll help pydantic a bit by parsing the
+        # primitive type ourselves, or pointing it at the correct
+        # complex type by looking at the type field
+
+        if isinstance(v, str):
+            if v.startswith("decimal"):
+                return DecimalType.parse(v)
+            elif v.startswith("fixed"):
+                return FixedType.parse(v)
+            else:
+                return PRIMITIVE_TYPES[v]
+        elif isinstance(v, dict):
+            if v.get("type") == "struct":
+                return StructType(**v)
+            elif v.get("type") == "list":
+                return ListType(**v)
+            elif v.get("type") == "map":
+                return MapType(**v)
+            else:
+                return NestedField(**v)
+        else:
+            return v
 
     @property
     def is_primitive(self) -> bool:
         return isinstance(self, PrimitiveType)
 
 
-@dataclass(frozen=True, eq=True)
 class PrimitiveType(IcebergType):
-    """Base class for all Iceberg Primitive Types
+    """Base class for all Iceberg Primitive Types"""
 
-    Example:
-        >>> str(PrimitiveType())
-        'PrimitiveType()'
-    """
+    __root__: str = Field()
+
+    def __repr__(self) -> str:
+        return f"{type(self).__name__}()"
+
+    def __str__(self) -> str:
+        return self.__root__
 
 
-@dataclass(frozen=True)
 class FixedType(PrimitiveType):
     """A fixed data type in Iceberg.
-
     Example:
         >>> FixedType(8)
         FixedType(length=8)
         >>> FixedType(8) == FixedType(8)
         True
+        >>> FixedType(19) == FixedType(25)
+        False
     """
 
-    length: int = field()
+    __root__: str = Field()
+    _length: int = PrivateAttr()
+
+    @staticmethod
+    def parse(str_repr: str) -> "FixedType":
+        matches = FIXED_REGEX.search(str_repr)
+        if matches:
+            length = int(matches.group(1))
+            return FixedType(length)
+        raise ValueError(f"Could not parse {str_repr} into a FixedType")
+
+    def __init__(self, length: int):
+        super().__init__(__root__=f"fixed[{length}]")
+        self._length = length
 
     @property
-    def string_type(self) -> str:
-        return f"fixed[{self.length}]"
+    def length(self) -> int:
+        return self._length
+
+    def __repr__(self) -> str:
+        return f"FixedType(length={self._length})"
 
 
-@dataclass(frozen=True, eq=True)
 class DecimalType(PrimitiveType):
     """A fixed data type in Iceberg.
-
     Example:
         >>> DecimalType(32, 3)
         DecimalType(precision=32, scale=3)
         >>> DecimalType(8, 3) == DecimalType(8, 3)
         True
     """
 
-    precision: int = field()
-    scale: int = field()
+    __root__: str = Field()
+
+    _precision: int = PrivateAttr()
+    _scale: int = PrivateAttr()
+
+    @staticmethod
+    def parse(str_repr: str) -> "DecimalType":
+        matches = DECIMAL_REGEX.search(str_repr)
+        if matches:
+            precision = int(matches.group(1))
+            scale = int(matches.group(2))
+            return DecimalType(precision, scale)
+        else:
+            raise ValueError(f"Could not parse {str_repr} into a DecimalType")
+
+    def __init__(self, precision: int, scale: int):
+        super().__init__(
+            __root__=f"decimal({precision}, {scale})",
+        )
+        self._precision = precision
+        self._scale = scale
+
+    @property
+    def precision(self) -> int:
+        return self._precision
 
     @property
-    def string_type(self) -> str:
-        return f"decimal({self.precision}, {self.scale})"
+    def scale(self) -> int:
+        return self._scale
+
+    def __repr__(self) -> str:
+        return f"DecimalType(precision={self._precision}, scale={self._scale})"
 
 
-@dataclass(frozen=True)
 class NestedField(IcebergType):
     """Represents a field of a struct, a map key, a map value, or a list 
element.
 
     This is where field IDs, names, docs, and nullability are tracked.
-

Review Comment:
   I blame my new keyboard, thanks!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to