You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by fo...@apache.org on 2023/08/04 11:42:25 UTC
[iceberg] branch master updated: Python: Add support `date`, `time` and `datetime` in to_bytes (#8214)
This is an automated email from the ASF dual-hosted git repository.
fokko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/master by this push:
new b34f4f2356 Python: Add support `date`, `time` and `datetime` in to_bytes (#8214)
b34f4f2356 is described below
commit b34f4f2356b9ee3cc5b5b5ce0eff554dc5f862d0
Author: Rishabh Srivastava <ri...@gmail.com>
AuthorDate: Fri Aug 4 17:12:19 2023 +0530
Python: Add support `date`, `time` and `datetime` in to_bytes (#8214)
* added datetime support for to_bytes
* fmt
* resuing datetime_to_micros
* removed unused imports
* added new test cases
* fixed format
* removed type checking
* added new test function
* removed old test cases
* datetypes added in function argument
---------
Co-authored-by: Rishabh Srivastava <ri...@cmd.com.au>
---
python/pyiceberg/conversions.py | 30 ++++++++++++++++++++++++++----
python/tests/test_conversions.py | 23 ++++++++++++++++++++++-
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/python/pyiceberg/conversions.py b/python/pyiceberg/conversions.py
index 26ec71475d..ebf6cfa666 100644
--- a/python/pyiceberg/conversions.py
+++ b/python/pyiceberg/conversions.py
@@ -28,6 +28,7 @@ Note:
implementations that share the same conversion logic, registrations can be stacked.
"""
import uuid
+from datetime import date, datetime, time
from decimal import Decimal
from functools import singledispatch
from struct import Struct
@@ -56,6 +57,7 @@ from pyiceberg.types import (
TimeType,
UUIDType,
)
+from pyiceberg.utils.datetime import date_to_days, datetime_to_micros, time_object_to_micros
from pyiceberg.utils.decimal import decimal_to_bytes, unscaled_to_decimal
_BOOL_STRUCT = Struct("<?")
@@ -152,7 +154,9 @@ def _(_: DecimalType, value_str: str) -> Decimal:
@singledispatch
-def to_bytes(primitive_type: PrimitiveType, _: Union[bool, bytes, Decimal, float, int, str, uuid.UUID]) -> bytes:
+def to_bytes(
+ primitive_type: PrimitiveType, _: Union[bool, bytes, Decimal, date, datetime, float, int, str, time, uuid.UUID]
+) -> bytes:
"""A generic function which converts a built-in python value to bytes.
This conversion follows the serialization scheme for storing single values as individual binary values defined in the Iceberg specification that
@@ -172,16 +176,34 @@ def _(_: BooleanType, value: bool) -> bytes:
@to_bytes.register(IntegerType)
-@to_bytes.register(DateType)
def _(_: PrimitiveType, value: int) -> bytes:
return _INT_STRUCT.pack(value)
@to_bytes.register(LongType)
-@to_bytes.register(TimeType)
+def _(_: PrimitiveType, value: int) -> bytes:
+ return _LONG_STRUCT.pack(value)
+
+
@to_bytes.register(TimestampType)
@to_bytes.register(TimestamptzType)
-def _(_: PrimitiveType, value: int) -> bytes:
+def _(_: TimestampType, value: Union[datetime, int]) -> bytes:
+ if isinstance(value, datetime):
+ value = datetime_to_micros(value)
+ return _LONG_STRUCT.pack(value)
+
+
+@to_bytes.register(DateType)
+def _(_: DateType, value: Union[date, int]) -> bytes:
+ if isinstance(value, date):
+ value = date_to_days(value)
+ return _INT_STRUCT.pack(value)
+
+
+@to_bytes.register(TimeType)
+def _(_: TimeType, value: Union[time, int]) -> bytes:
+ if isinstance(value, time):
+ value = time_object_to_micros(value)
return _LONG_STRUCT.pack(value)
diff --git a/python/tests/test_conversions.py b/python/tests/test_conversions.py
index 94f553741f..429de6e011 100644
--- a/python/tests/test_conversions.py
+++ b/python/tests/test_conversions.py
@@ -73,8 +73,14 @@ Notes:
"""
import struct
import uuid
+from datetime import (
+ date,
+ datetime,
+ time,
+ timezone,
+)
from decimal import Decimal
-from typing import Any
+from typing import Any, Union
import pytest
@@ -507,3 +513,18 @@ def test_raise_on_incorrect_precision_or_scale(primitive_type: DecimalType, valu
conversions.to_bytes(primitive_type, value)
assert expected_error_message in str(exc_info.value)
+
+
+@pytest.mark.parametrize(
+ "primitive_type, value, expected_bytes",
+ [
+ (TimestampType(), datetime(2023, 3, 1, 19, 25, 0), b"\x00\xbb\r\xab\xdb\xf5\x05\x00"),
+ (TimestamptzType(), datetime(2023, 3, 1, 19, 25, 0, tzinfo=timezone.utc), b"\x00\xbb\r\xab\xdb\xf5\x05\x00"),
+ (DateType(), date(2023, 3, 1), b"\xd9K\x00\x00"),
+ (TimeType(), time(12, 30, 45, 500000), b"`\xc8\xeb|\n\x00\x00\x00"),
+ ],
+)
+def test_datetime_obj_to_bytes(primitive_type: PrimitiveType, value: Union[datetime, date, time], expected_bytes: bytes) -> None:
+ bytes_from_value = conversions.to_bytes(primitive_type, value)
+
+ assert bytes_from_value == expected_bytes