diff --git a/CHANGELOG.md b/CHANGELOG.md index a0c1e837..d01b2672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [6.0.2] - 2026-02-19 + +### Fixed +- Fixed `dataframe_from_result_table` crashing with pandas 3.0 when a datetime column contains all null values. +- Removed legacy pandas 1.x code path in `parse_datetime` (minimum supported pandas is now 2.3.1). + ## [6.0.1] - 2025-12-25 ### Fixed diff --git a/azure-kusto-data/azure/kusto/data/helpers.py b/azure-kusto-data/azure/kusto/data/helpers.py index d09613aa..1547cbf8 100644 --- a/azure-kusto-data/azure/kusto/data/helpers.py +++ b/azure-kusto-data/azure/kusto/data/helpers.py @@ -119,19 +119,10 @@ def parse_float(frame, col): return frame[col] -def parse_datetime(frame, col, force_version: Optional[str] = None) -> "pd.Series": - # Pandas before version 2 doesn't support the "format" arg +def parse_datetime(frame, col) -> "pd.Series": import pandas as pd - args = {} - if (force_version or pd.__version__).startswith("2."): - args = {"format": "ISO8601", "utc": True} - else: - # if frame contains ".", replace "Z" with ".000Z" - # Using bitwise NOT (~) on the boolean Series is the idiomatic pandas way to negate the mask - contains_dot = frame[col].str.contains("\\.") - frame.loc[~contains_dot, col] = frame.loc[~contains_dot, col].str.replace("Z", ".000Z") - frame[col] = pd.to_datetime(frame[col], errors="coerce", **args) + frame[col] = pd.to_datetime(frame[col], format="ISO8601", utc=True, errors="coerce") return frame[col] diff --git a/azure-kusto-data/pyproject.toml b/azure-kusto-data/pyproject.toml index 80e5b63e..d03daf5d 100644 --- a/azure-kusto-data/pyproject.toml +++ b/azure-kusto-data/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "azure-kusto-data" -version = "6.0.1" +version = "6.0.2" description = "Kusto Data Client" authors = [ { name = "Microsoft Corporation", email = "kustalk@microsoft.com" }, diff --git a/azure-kusto-data/tests/test_helpers.py b/azure-kusto-data/tests/test_helpers.py index b9cf4bae..6ee4043c 100644 --- a/azure-kusto-data/tests/test_helpers.py +++ b/azure-kusto-data/tests/test_helpers.py @@ -131,28 +131,38 @@ def test_pandas_mixed_date(): def test_datetime_parsing(): - """Test parse_datetime function with different pandas versions and datetime formats""" - - # Test with pandas v2 behavior (force version 2) - df_v2 = pandas.DataFrame( + """Test parse_datetime correctly parses mixed datetime formats""" + df = pandas.DataFrame( { "mixed": ["2023-12-12T01:59:59.352Z", "2023-12-12T01:54:44Z"], } ) - # Force pandas v2 behavior - result_v2 = parse_datetime(df_v2, "mixed", force_version="2.0.0") - assert str(result_v2[0]) == "2023-12-12 01:59:59.352000+00:00" - assert str(result_v2[1]) == "2023-12-12 01:54:44+00:00" - # Test with pandas v1 behavior (force version 1) + result = parse_datetime(df, "mixed") + assert str(result[0]) == "2023-12-12 01:59:59.352000+00:00" + assert str(result[1]) == "2023-12-12 01:54:44+00:00" - df_v1 = pandas.DataFrame( - { - "mixed": ["2023-12-12T01:59:59.352Z", "2023-12-12T01:54:44Z"], - } + +def test_all_null_datetime_column(): + """Test dataframe_from_result_table with a column where all datetime values are null (pandas 3.0 regression)""" + df = dataframe_from_result_table( + KustoResultTable( + { + "TableName": "Table_0", + "Columns": [ + {"ColumnName": "timestamp", "ColumnType": "datetime"}, + {"ColumnName": "value", "ColumnType": "real"}, + ], + "Rows": [ + [None, 10], + [None, 11], + ], + } + ) ) - # Force pandas v1 behavior - it should add .000 to dates without milliseconds - result_v1 = parse_datetime(df_v1, "mixed", force_version="1.5.3") - assert str(result_v1[0]) == "2023-12-12 01:59:59.352000+00:00" - assert str(result_v1[1]) == "2023-12-12 01:54:44+00:00" + assert len(df) == 2 + assert pandas.isnull(df["timestamp"][0]) + assert pandas.isnull(df["timestamp"][1]) + assert df["value"][0] == 10 + assert df["value"][1] == 11 diff --git a/azure-kusto-ingest/pyproject.toml b/azure-kusto-ingest/pyproject.toml index 93da12ae..6e3d4a62 100644 --- a/azure-kusto-ingest/pyproject.toml +++ b/azure-kusto-ingest/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "azure-kusto-ingest" -version = "6.0.1" +version = "6.0.2" description = "Kusto Ingest Client" authors = [ { name = "Microsoft Corporation", email = "kustalk@microsoft.com" }, diff --git a/pyproject.toml b/pyproject.toml index e30897a7..e8060efa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "azure-kusto-python" -version = "6.0.1" +version = "6.0.2" description = "Microsoft Azure Kusto Python SDK" dependencies = [ "azure-kusto-data", diff --git a/quick-start/pyproject.toml b/quick-start/pyproject.toml index c13d13bf..400db5eb 100644 --- a/quick-start/pyproject.toml +++ b/quick-start/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "quick-start" -version = "6.0.1" +version = "6.0.2" description = "Microsoft Azure Kusto Python SDK" dependencies = [ "azure-kusto-data",