From 3d9e865ab3badd092d8155302641a3e91c72c028 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Tue, 18 Jan 2022 10:04:13 -0500 Subject: [PATCH] feat: allow construction of decimal literals --- ibis/expr/datatypes.py | 6 ++++++ ibis/expr/operations/generic.py | 2 ++ ibis/tests/expr/test_value_exprs.py | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/ibis/expr/datatypes.py b/ibis/expr/datatypes.py index 2ac2aa6d709c..98f48efac2c2 100644 --- a/ibis/expr/datatypes.py +++ b/ibis/expr/datatypes.py @@ -4,6 +4,7 @@ import builtins import collections import datetime +import decimal import enum import functools import itertools @@ -1571,3 +1572,8 @@ def _str_to_uuid(typ: UUID, value: str) -> _uuid.UUID: @_normalize.register(String, _uuid.UUID) def _uuid_to_str(typ: String, value: _uuid.UUID) -> str: return str(value) + + +@_normalize.register(Decimal, int) +def _int_to_decimal(typ: Decimal, value: int) -> decimal.Decimal: + return decimal.Decimal(value).scaleb(-typ.scale) diff --git a/ibis/expr/operations/generic.py b/ibis/expr/operations/generic.py index cbc31f47a9d1..39bd4b74727b 100644 --- a/ibis/expr/operations/generic.py +++ b/ibis/expr/operations/generic.py @@ -1,4 +1,5 @@ import datetime +import decimal import enum import functools import itertools @@ -242,6 +243,7 @@ class Literal(ValueOp): tuple, type(None), uuid.UUID, + decimal.Decimal, ) ), rlz.is_computable_input, diff --git a/ibis/tests/expr/test_value_exprs.py b/ibis/tests/expr/test_value_exprs.py index 79132805459f..ae5a90bf1b5b 100644 --- a/ibis/tests/expr/test_value_exprs.py +++ b/ibis/tests/expr/test_value_exprs.py @@ -4,6 +4,7 @@ import uuid from collections import OrderedDict from datetime import date, datetime, time +from decimal import Decimal from operator import methodcaller import numpy as np @@ -112,6 +113,8 @@ def test_literal_with_implicit_type(value, expected_type): (tuple(multipolygon1), 'multipolygon'), pytest.param(uuid.uuid4(), 'uuid', id='uuid'), pytest.param(str(uuid.uuid4()), 'uuid', id='uuid_str'), + pytest.param(Decimal("234.234"), "decimal(6, 3)", id="decimal_native"), + pytest.param(234234, "decimal(6, 3)", id="decimal_int"), ], ) def test_literal_with_explicit_type(value, expected_type): @@ -119,6 +122,25 @@ def test_literal_with_explicit_type(value, expected_type): assert expr.type().equals(dt.validate_type(expected_type)) +@pytest.mark.parametrize( + ("value", "expected", "dtype"), + [ + # precision > scale + (Decimal("234.234"), Decimal("234.234"), "decimal(6, 3)"), + (234234, Decimal("234.234"), "decimal(6, 3)"), + # scale == 0 + (Decimal("234"), Decimal("234"), "decimal(6, 0)"), + (234, Decimal("234"), "decimal(6, 0)"), + # precision == scale + (Decimal(".234"), Decimal(".234"), "decimal(3, 3)"), + (234, Decimal(".234"), "decimal(3, 3)"), + ], +) +def test_normalize_decimal_literal(value, expected, dtype): + expr = ibis.literal(value, type=dtype) + assert expr.op().value == expected + + @pytest.mark.parametrize( ['value', 'expected_type', 'expected_class'], [