Skip to content

Commit a0158ce

Browse files
feat: Allow comparing different categoricals by casting to strings (#49)
1 parent 5c5dfd0 commit a0158ce

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

diffly/_conditions.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,10 @@ def _compare_columns(
153153
)
154154
return col_left.eq_missing(col_right)
155155

156-
if _different_enums(dtype_left, dtype_right) or _enum_and_categorical(
157-
dtype_left, dtype_right
156+
if (
157+
_different_enums(dtype_left, dtype_right)
158+
or _different_categoricals(dtype_left, dtype_right)
159+
or _enum_and_categorical(dtype_left, dtype_right)
158160
):
159161
# Enums with different categories as well as enums and categoricals
160162
# can't be compared directly.
@@ -267,6 +269,7 @@ def _needs_element_wise_comparison(
267269
_is_float_numeric_pair(dtype_left, dtype_right)
268270
or _is_temporal_pair(dtype_left, dtype_right)
269271
or _different_enums(dtype_left, dtype_right)
272+
or _different_categoricals(dtype_left, dtype_right)
270273
or _enum_and_categorical(dtype_left, dtype_right)
271274
):
272275
return True
@@ -322,6 +325,16 @@ def _different_enums(
322325
return isinstance(left, pl.Enum) and isinstance(right, pl.Enum) and left != right
323326

324327

328+
def _different_categoricals(
329+
left: DataType | DataTypeClass, right: DataType | DataTypeClass
330+
) -> bool:
331+
return (
332+
isinstance(left, pl.Categorical)
333+
and isinstance(right, pl.Categorical)
334+
and left != right
335+
)
336+
337+
325338
def _enum_and_categorical(
326339
left: DataType | DataTypeClass, right: DataType | DataTypeClass
327340
) -> bool:

tests/test_conditions.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,43 @@ def test_condition_equal_columns_list_of_different_enums() -> None:
555555
assert actual.to_list() == [True, False]
556556

557557

558+
def test_condition_equal_columns_different_categorical() -> None:
559+
# Arrange
560+
fruits = pl.Categorical(categories=pl.Categories(name="fruits"))
561+
fruit = pl.Categorical(categories=pl.Categories(name="fruit"))
562+
563+
lhs = pl.DataFrame(
564+
{"pk": [1, 2], "a": ["apple", "orange"]},
565+
schema_overrides={"a": fruits},
566+
)
567+
rhs = pl.DataFrame(
568+
{"pk": [1, 2], "a": ["apple", "banana"]},
569+
schema_overrides={"a": fruit},
570+
)
571+
c = compare_frames(lhs, rhs, primary_key="pk")
572+
573+
# Act
574+
lhs = lhs.rename({"a": "a_left"})
575+
rhs = rhs.rename({"a": "a_right"})
576+
actual = (
577+
lhs.join(rhs, on="pk", maintain_order="left")
578+
.select(
579+
condition_equal_columns(
580+
"a",
581+
dtype_left=lhs.schema["a_left"],
582+
dtype_right=rhs.schema["a_right"],
583+
max_list_length=None,
584+
abs_tol=c.abs_tol_by_column["a"],
585+
rel_tol=c.rel_tol_by_column["a"],
586+
)
587+
)
588+
.to_series()
589+
)
590+
591+
# Assert
592+
assert actual.to_list() == [True, False]
593+
594+
558595
@pytest.mark.parametrize(
559596
("dtype_left", "dtype_right", "can_compare_dtypes"),
560597
[

0 commit comments

Comments
 (0)