Skip to content

Commit

Permalink
fix: Fix one edge case (out of many) of int128 literals not working (#…
Browse files Browse the repository at this point in the history
…20830)

Co-authored-by: Itamar Turner-Trauring <[email protected]>
  • Loading branch information
itamarst and pythonspeed authored Jan 22, 2025
1 parent 9c1637c commit f79ea83
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 13 deletions.
25 changes: 16 additions & 9 deletions crates/polars-core/src/utils/supertype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,17 +537,24 @@ fn super_type_structs(fields_a: &[Field], fields_b: &[Field]) -> Option<DataType
pub fn materialize_dyn_int(v: i128) -> AnyValue<'static> {
// Try to get the "smallest" fitting value.
// TODO! next breaking go to true smallest.
match i32::try_from(v).ok() {
Some(v) => AnyValue::Int32(v),
None => match i64::try_from(v).ok() {
Some(v) => AnyValue::Int64(v),
None => match u64::try_from(v).ok() {
Some(v) => AnyValue::UInt64(v),
None => AnyValue::Null,
},
},
if let Ok(v) = i32::try_from(v) {
return AnyValue::Int32(v);
}
if let Ok(v) = i64::try_from(v) {
return AnyValue::Int64(v);
}
if let Ok(v) = u64::try_from(v) {
return AnyValue::UInt64(v);
}
#[cfg(feature = "dtype-i128")]
{
AnyValue::Int128(v)
}

#[cfg(not(feature = "dtype-i128"))]
AnyValue::Null
}

fn materialize_dyn_int_pos(v: i128) -> AnyValue<'static> {
// Try to get the "smallest" fitting value.
// TODO! next breaking go to true smallest.
Expand Down
9 changes: 9 additions & 0 deletions py-polars/tests/unit/expr/test_literal.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ def test_literal_scalar_list_18686() -> None:
("lit2", pl.List(pl.Null)),
]
)


def test_literal_integer_20807() -> None:
for i in range(100):
value = 2**i
assert pl.select(pl.lit(value)).item() == value
assert pl.select(pl.lit(-value)).item() == -value
assert pl.select(pl.lit(value, dtype=pl.Int128)).item() == value
assert pl.select(pl.lit(-value, dtype=pl.Int128)).item() == -value
33 changes: 29 additions & 4 deletions py-polars/tests/unit/operations/test_index_of.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,21 @@
from polars.testing import assert_frame_equal


def isnan(value: object) -> bool:
if isinstance(value, int):
return False
if not isinstance(value, (np.number, float)):
return False
return np.isnan(value) # type: ignore[no-any-return]


def assert_index_of(
series: pl.Series,
value: IntoExpr,
convert_to_literal: bool = False,
) -> None:
"""``Series.index_of()`` returns the index, or ``None`` if it can't be found."""
if isinstance(value, (np.number, float, int)) and np.isnan(value):
if isnan(value):
expected_index = None
for i, o in enumerate(series.to_list()):
if o is not None and np.isnan(o):
Expand Down Expand Up @@ -93,18 +101,35 @@ def test_empty() -> None:

@pytest.mark.parametrize(
"dtype",
[pl.Int8, pl.Int16, pl.Int32, pl.Int64, pl.UInt8, pl.UInt16, pl.UInt32, pl.UInt64],
[
pl.Int8,
pl.Int16,
pl.Int32,
pl.Int64,
pl.UInt8,
pl.UInt16,
pl.UInt32,
pl.UInt64,
pl.Int128,
],
)
def test_integer(dtype: pl.DataType) -> None:
values = [51, 3, None, 4]
values = [
51,
3,
None,
4,
pl.select(dtype.max()).item(), # type: ignore[attr-defined]
pl.select(dtype.min()).item(), # type: ignore[attr-defined]
]
series = pl.Series(values, dtype=dtype)
sorted_series_asc = series.sort(descending=False)
sorted_series_desc = series.sort(descending=True)
chunked_series = pl.concat(
[pl.Series([100, 7], dtype=dtype), series], rechunk=False
)

extra_values = [pl.select(v).item() for v in [dtype.max(), dtype.min()]] # type: ignore[attr-defined]
extra_values = [pl.select(v).item() for v in [dtype.max() - 1, dtype.min() + 1]] # type: ignore[attr-defined]
for s in [series, sorted_series_asc, sorted_series_desc, chunked_series]:
value: IntoExpr
for value in values:
Expand Down

0 comments on commit f79ea83

Please sign in to comment.