blob: c974fc8b5204c68c69c5dee81874fcd9d0755f03 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint:disable=eval-used
import datetime
import uuid
from decimal import Decimal
from typing import (
Any,
List,
Set,
Type,
)
import pytest
from typing_extensions import assert_type
from pyiceberg.expressions.literals import (
BinaryLiteral,
BooleanLiteral,
DateLiteral,
DecimalLiteral,
DoubleLiteral,
FixedLiteral,
FloatAboveMax,
FloatBelowMin,
FloatLiteral,
IntAboveMax,
IntBelowMin,
Literal,
LongLiteral,
StringLiteral,
TimeLiteral,
TimestampLiteral,
literal,
)
from pyiceberg.types import (
BinaryType,
BooleanType,
DateType,
DecimalType,
DoubleType,
FixedType,
FloatType,
IntegerType,
LongType,
PrimitiveType,
StringType,
TimestampType,
TimestamptzType,
TimeType,
UUIDType,
)
def test_literal_from_none_error() -> None:
with pytest.raises(TypeError) as e:
literal(None) # type: ignore
assert "Invalid literal value: None" in str(e.value)
def test_literal_from_nan_error() -> None:
with pytest.raises(ValueError) as e:
literal(float("nan"))
assert "Cannot create expression literal from NaN." in str(e.value)
@pytest.mark.parametrize(
"literal_class",
[
BooleanLiteral,
LongLiteral,
FloatLiteral,
DoubleLiteral,
DateLiteral,
TimeLiteral,
TimestampLiteral,
DecimalLiteral,
StringLiteral,
FixedLiteral,
BinaryLiteral,
],
)
def test_literal_classes_with_none_type_error(literal_class: Type[PrimitiveType]) -> None:
with pytest.raises(TypeError) as e:
literal_class(None)
assert "Invalid literal value: None" in str(e.value)
@pytest.mark.parametrize("literal_class", [FloatLiteral, DoubleLiteral])
def test_literal_classes_with_nan_value_error(literal_class: Type[PrimitiveType]) -> None:
with pytest.raises(ValueError) as e:
literal_class(float("nan"))
assert "Cannot create expression literal from NaN." in str(e.value)
# Numeric
def test_numeric_literal_comparison() -> None:
small_lit = literal(10).to(IntegerType())
big_lit = literal(1000).to(IntegerType())
assert small_lit != big_lit
assert small_lit == literal(10)
assert small_lit < big_lit
assert small_lit <= big_lit
assert big_lit > small_lit
assert big_lit >= small_lit
def test_integer_to_long_conversion() -> None:
lit = literal(34).to(IntegerType())
long_lit = lit.to(LongType())
assert lit.value == long_lit.value
def test_integer_to_float_conversion() -> None:
lit = literal(34).to(IntegerType())
float_lit = lit.to(FloatType())
assert lit.value == float_lit.value
def test_integer_to_double_conversion() -> None:
lit = literal(34).to(IntegerType())
dbl_lit = lit.to(DoubleType())
assert lit.value == dbl_lit.value
@pytest.mark.parametrize(
"decimal_type, decimal_value", [(DecimalType(9, 0), "34"), (DecimalType(9, 2), "34.00"), (DecimalType(9, 4), "34.0000")]
)
def test_integer_to_decimal_conversion(decimal_type: DecimalType, decimal_value: str) -> None:
lit = literal(34).to(IntegerType())
assert lit.to(decimal_type).value.as_tuple() == Decimal(decimal_value).as_tuple() # type: ignore
def test_integer_to_date_conversion() -> None:
one_day = "2022-03-28"
date_delta = (datetime.date.fromisoformat(one_day) - datetime.date.fromisoformat("1970-01-01")).days
date_lit = literal(date_delta).to(DateType())
assert isinstance(date_lit, DateLiteral)
assert date_lit.value == date_delta
def test_long_to_integer_within_bound() -> None:
lit = literal(34).to(LongType())
int_lit = lit.to(IntegerType())
assert lit.value == int_lit.value
def test_long_to_integer_outside_bound() -> None:
big_lit = literal(IntegerType.max + 1).to(LongType())
above_max_lit = big_lit.to(IntegerType())
assert above_max_lit == IntAboveMax()
small_lit = literal(IntegerType.min - 1).to(LongType())
below_min_lit = small_lit.to(IntegerType())
assert below_min_lit == IntBelowMin()
def test_long_to_float_conversion() -> None:
lit = literal(34).to(LongType())
float_lit = lit.to(FloatType())
assert lit.value == float_lit.value
def test_long_to_double_conversion() -> None:
lit = literal(34).to(LongType())
dbl_lit = lit.to(DoubleType())
assert lit.value == dbl_lit.value
def test_long_to_time() -> None:
long_lit = literal(51661919000).to(LongType())
time_lit = long_lit.to(TimeType())
assert isinstance(time_lit, TimeLiteral)
assert time_lit.value == long_lit.value
def test_long_to_timestamp() -> None:
long_lit = literal(1647305201).to(LongType())
timestamp_lit = long_lit.to(TimestampType())
assert timestamp_lit.value == long_lit.value
@pytest.mark.parametrize(
"decimal_type, decimal_value", [(DecimalType(9, 0), "34"), (DecimalType(9, 2), "34.00"), (DecimalType(9, 4), "34.0000")]
)
def test_long_to_decimal_conversion(decimal_type: DecimalType, decimal_value: str) -> None:
lit = literal(34).to(LongType())
assert lit.to(decimal_type).value.as_tuple() == Decimal(decimal_value).as_tuple() # type: ignore
def test_float_to_double() -> None:
lit = literal(34.56).to(FloatType())
dbl_lit = lit.to(DoubleType())
assert lit.value == dbl_lit.value
@pytest.mark.parametrize(
"decimal_type, decimal_value", [(DecimalType(9, 1), "34.6"), (DecimalType(9, 2), "34.56"), (DecimalType(9, 4), "34.5600")]
)
def test_float_to_decimal_conversion(decimal_type: DecimalType, decimal_value: str) -> None:
lit = literal(34.56).to(FloatType())
assert lit.to(decimal_type).value.as_tuple() == Decimal(decimal_value).as_tuple() # type: ignore
def test_double_to_float_within_bound() -> None:
lit = literal(34.56).to(DoubleType())
float_lit = lit.to(FloatType())
assert lit.value == float_lit.value
def test_double_to_float_outside_bound() -> None:
big_lit = literal(FloatType.max + 1.0e37).to(DoubleType())
above_max_lit = big_lit.to(FloatType())
assert above_max_lit == FloatAboveMax()
small_lit = literal(FloatType.min - 1.0e37).to(DoubleType())
below_min_lit = small_lit.to(FloatType())
assert below_min_lit == FloatBelowMin()
@pytest.mark.parametrize(
"decimal_type, decimal_value", [(DecimalType(9, 1), "34.6"), (DecimalType(9, 2), "34.56"), (DecimalType(9, 4), "34.5600")]
)
def test_double_to_decimal_conversion(decimal_type: DecimalType, decimal_value: str) -> None:
lit = literal(34.56).to(DoubleType())
assert lit.to(decimal_type).value.as_tuple() == Decimal(decimal_value).as_tuple() # type: ignore
def test_decimal_to_decimal_conversion() -> None:
lit = literal(Decimal("34.11").quantize(Decimal(".01")))
assert lit.value.as_tuple() == lit.to(DecimalType(9, 2)).value.as_tuple()
assert lit.value.as_tuple() == lit.to(DecimalType(11, 2)).value.as_tuple()
with pytest.raises(ValueError) as e:
_ = lit.to(DecimalType(9, 0))
assert "Could not convert 34.11 into a decimal(9, 0)" in str(e.value)
with pytest.raises(ValueError) as e:
_ = lit.to(DecimalType(9, 1))
assert "Could not convert 34.11 into a decimal(9, 1)" in str(e.value)
with pytest.raises(ValueError) as e:
_ = lit.to(DecimalType(9, 3))
assert "Could not convert 34.11 into a decimal(9, 3)" in str(e.value)
def test_timestamp_to_date() -> None:
epoch_lit = TimestampLiteral(int(datetime.datetime.fromisoformat("1970-01-01T01:23:45.678").timestamp() * 1_000_000))
date_lit = epoch_lit.to(DateType())
assert date_lit.value == 0
def test_string_literal() -> None:
sqrt2 = literal("1.414").to(StringType())
pi = literal("3.141").to(StringType())
pi_string_lit = StringLiteral("3.141")
pi_double_lit = literal(3.141).to(DoubleType())
assert literal("3.141").to(IntegerType()) == literal(3)
assert literal("3.141").to(LongType()) == literal(3)
assert sqrt2 != pi
assert pi != pi_double_lit
assert pi == pi_string_lit
assert pi == pi
assert sqrt2 < pi
assert sqrt2 <= pi
assert pi > sqrt2
assert pi >= sqrt2
assert str(pi) == "3.141"
def test_string_to_string_literal() -> None:
assert literal("abc") == literal("abc").to(StringType())
def test_string_to_date_literal() -> None:
one_day = "2017-08-18"
date_lit = literal(one_day).to(DateType())
date_delta = (datetime.date.fromisoformat(one_day) - datetime.date.fromisoformat("1970-01-01")).days
assert date_delta == date_lit.value
def test_string_to_time_literal() -> None:
time_str = literal("14:21:01.919")
time_lit = time_str.to(TimeType())
avro_val = 51661919000
assert isinstance(time_lit, TimeLiteral) # type: ignore
assert avro_val == time_lit.value # type: ignore
def test_string_to_timestamp_literal() -> None:
timestamp_str = literal("2017-08-18T14:21:01.919234+00:00")
timestamp = timestamp_str.to(TimestamptzType())
avro_val = 1503066061919234
assert avro_val == timestamp.value
timestamp_str = literal("2017-08-18T14:21:01.919234")
timestamp = timestamp_str.to(TimestampType())
assert avro_val == timestamp.value
timestamp_str = literal("2017-08-18T14:21:01.919234-07:00")
timestamp = timestamp_str.to(TimestamptzType())
avro_val = 1503091261919234
assert avro_val == timestamp.value
def test_timestamp_with_zone_without_zone_in_literal() -> None:
timestamp_str = literal("2017-08-18T14:21:01.919234")
with pytest.raises(ValueError) as e:
_ = timestamp_str.to(timestamp_str.to(TimestamptzType()))
assert "Missing zone offset: 2017-08-18T14:21:01.919234 (must be ISO-8601)" in str(e.value)
def test_invalid_timestamp_in_literal() -> None:
timestamp_str = literal("abc")
with pytest.raises(ValueError) as e:
_ = timestamp_str.to(timestamp_str.to(TimestamptzType()))
assert "Invalid timestamp with zone: abc (must be ISO-8601)" in str(e.value)
def test_timestamp_without_zone_with_zone_in_literal() -> None:
timestamp_str = literal("2017-08-18T14:21:01.919234+07:00")
with pytest.raises(ValueError) as e:
_ = timestamp_str.to(TimestampType())
assert "Zone offset provided, but not expected: 2017-08-18T14:21:01.919234+07:00" in str(e.value)
def test_invalid_timestamp_with_zone_in_literal() -> None:
timestamp_str = literal("abc")
with pytest.raises(ValueError) as e:
_ = timestamp_str.to(TimestampType())
assert "Invalid timestamp without zone: abc (must be ISO-8601)" in str(e.value)
def test_string_to_uuid_literal() -> None:
expected = uuid.uuid4()
uuid_str = literal(str(expected))
uuid_lit = uuid_str.to(UUIDType())
assert expected.bytes == uuid_lit.value
def test_string_to_decimal_literal() -> None:
decimal_str = literal("34.560")
decimal_lit = decimal_str.to(DecimalType(9, 3))
assert 3 == abs(decimal_lit.value.as_tuple().exponent) # type: ignore
assert Decimal("34.560").as_tuple() == decimal_lit.value.as_tuple() # type: ignore
def test_string_to_boolean_literal() -> None:
assert literal(True) == literal("true").to(BooleanType())
assert literal(True) == literal("True").to(BooleanType())
assert literal(False) == literal("false").to(BooleanType())
assert literal(False) == literal("False").to(BooleanType())
def test_invalid_string_to_boolean_literal() -> None:
invalid_boolean_str = literal("unknown")
with pytest.raises(ValueError) as e:
_ = invalid_boolean_str.to(BooleanType())
assert "Could not convert unknown into a boolean" in str(e.value)
# MISC
def test_python_date_conversion() -> None:
one_day_str = "2022-03-28"
from_str_lit = literal(one_day_str).to(DateType())
assert isinstance(from_str_lit, DateLiteral) # type: ignore
assert from_str_lit.value == 19079 # type: ignore
@pytest.mark.parametrize(
"lit, primitive_type",
[
(literal(True), BooleanType()),
(literal(34), IntegerType()),
(literal(3400000000), LongType()),
(literal(34.11), FloatType()),
(literal(3.5028235e38), DoubleType()),
(literal(Decimal(34.55).quantize(Decimal("0.01"))), DecimalType(9, 2)),
(literal("2017-08-18"), DateType()),
(literal("14:21:01.919"), TimeType()),
(literal("2017-08-18T14:21:01.919"), TimestampType()),
(literal("abc"), StringType()),
(literal(uuid.uuid4()), UUIDType()),
(literal(bytes([0x01, 0x02, 0x03])), FixedType(3)),
],
)
def test_identity_conversions(lit: Literal[Any], primitive_type: PrimitiveType) -> None:
expected = lit.to(primitive_type)
assert expected is expected.to(primitive_type)
def test_fixed_literal() -> None:
fixed_lit012 = literal(bytes([0x00, 0x01, 0x02]))
fixed_lit013 = literal(bytes([0x00, 0x01, 0x03]))
assert fixed_lit012 == fixed_lit012
assert fixed_lit012 != fixed_lit013
assert fixed_lit012 < fixed_lit013
assert fixed_lit012 <= fixed_lit013
assert fixed_lit013 > fixed_lit012
assert fixed_lit013 >= fixed_lit012
def test_binary_literal() -> None:
bin_lit012 = literal(bytes([0x00, 0x01, 0x02]))
bin_lit013 = literal(bytes([0x00, 0x01, 0x03]))
assert bin_lit012 == bin_lit012
assert bin_lit012 != bin_lit013
assert bin_lit012 < bin_lit013
assert bin_lit012 <= bin_lit013
assert bin_lit013 > bin_lit012
assert bin_lit013 >= bin_lit012
# None related
def test_raise_on_comparison_to_none() -> None:
bin_lit012 = literal(bytes([0x00, 0x01, 0x02]))
fixed_lit012 = literal(bytes([0x00, 0x01, 0x02]))
with pytest.raises(AttributeError):
_ = bin_lit012 < None
with pytest.raises(AttributeError):
_ = bin_lit012 <= None
with pytest.raises(AttributeError):
_ = bin_lit012 > None
with pytest.raises(AttributeError):
_ = bin_lit012 >= None
with pytest.raises(AttributeError):
_ = fixed_lit012 < None
with pytest.raises(AttributeError):
_ = fixed_lit012 <= None
with pytest.raises(AttributeError):
_ = fixed_lit012 > None
with pytest.raises(AttributeError):
_ = fixed_lit012 >= None
def test_binary_to_fixed() -> None:
lit = literal(bytes([0x00, 0x01, 0x02]))
fixed_lit = lit.to(FixedType(3))
assert fixed_lit is not None
assert lit.value == fixed_lit.value
with pytest.raises(TypeError) as e:
_ = lit.to(FixedType(4))
assert "Cannot convert BinaryLiteral into fixed[4], different length: 4 <> 3" in str(e.value)
def test_binary_to_smaller_fixed_none() -> None:
lit = literal(bytes([0x00, 0x01, 0x02]))
with pytest.raises(TypeError) as e:
_ = lit.to(FixedType(2))
assert "Cannot convert BinaryLiteral into fixed[2], different length: 2 <> 3" in str(e.value)
def test_binary_to_uuid() -> None:
test_uuid = uuid.uuid4()
lit = literal(test_uuid.bytes)
uuid_lit = lit.to(UUIDType())
assert uuid_lit is not None
assert lit.value == uuid_lit.value
assert uuid_lit.value == test_uuid.bytes
def test_incompatible_binary_to_uuid() -> None:
lit = literal(bytes([0x00, 0x01, 0x02]))
with pytest.raises(TypeError) as e:
_ = lit.to(UUIDType())
assert "Cannot convert BinaryLiteral into uuid, different length: 16 <> 3" in str(e.value)
def test_fixed_to_binary() -> None:
lit = literal(bytes([0x00, 0x01, 0x02])).to(FixedType(3))
binary_lit = lit.to(BinaryType())
assert binary_lit is not None
assert lit.value == binary_lit.value
def test_fixed_to_smaller_fixed_none() -> None:
lit = literal(bytes([0x00, 0x01, 0x02])).to(FixedType(3))
with pytest.raises(ValueError) as e:
lit.to(lit.to(FixedType(2)))
assert "Could not convert b'\\x00\\x01\\x02' into a fixed[2]" in str(e.value)
def test_fixed_to_uuid() -> None:
test_uuid = uuid.uuid4()
lit = literal(test_uuid.bytes).to(FixedType(16))
uuid_lit = lit.to(UUIDType())
assert uuid_lit is not None
assert lit.value == uuid_lit.value
assert uuid_lit.value == test_uuid.bytes
def test_incompatible_fixed_to_uuid() -> None:
lit = literal(bytes([0x00, 0x01, 0x02])).to(FixedType(3))
with pytest.raises(TypeError) as e:
_ = lit.to(UUIDType())
assert "Cannot convert BinaryLiteral into uuid, different length: 16 <> 3" in str(e.value)
def test_above_max_float() -> None:
a = FloatAboveMax()
# singleton
assert a == FloatAboveMax()
assert str(a) == "FloatAboveMax"
assert repr(a) == "FloatAboveMax()"
assert a.value == FloatType.max
assert a == eval(repr(a))
assert a.to(FloatType()) == FloatAboveMax()
def test_below_min_float() -> None:
b = FloatBelowMin()
# singleton
assert b == FloatBelowMin()
assert str(b) == "FloatBelowMin"
assert repr(b) == "FloatBelowMin()"
assert b == eval(repr(b))
assert b.value == FloatType.min
assert b.to(FloatType()) == FloatBelowMin()
def test_above_max_int() -> None:
a = IntAboveMax()
# singleton
assert a == IntAboveMax()
assert str(a) == "IntAboveMax"
assert repr(a) == "IntAboveMax()"
assert a.value == IntegerType.max
assert a == eval(repr(a))
assert a.to(IntegerType()) == IntAboveMax()
def test_below_min_int() -> None:
b = IntBelowMin()
# singleton
assert b == IntBelowMin()
assert str(b) == "IntBelowMin"
assert repr(b) == "IntBelowMin()"
assert b == eval(repr(b))
assert b.to(IntegerType()) == IntBelowMin()
def test_invalid_boolean_conversions() -> None:
assert_invalid_conversions(
literal(True),
[
IntegerType(),
LongType(),
FloatType(),
DoubleType(),
DateType(),
TimeType(),
TimestampType(),
TimestamptzType(),
DecimalType(9, 2),
StringType(),
UUIDType(),
BinaryType(),
],
)
def test_invalid_long_conversions() -> None:
assert_invalid_conversions(
literal(34).to(LongType()),
[BooleanType(), StringType(), UUIDType(), FixedType(1), BinaryType()],
)
@pytest.mark.parametrize(
"lit",
[
literal(34.11).to(FloatType()),
# double
literal(34.11).to(DoubleType()),
],
)
@pytest.mark.parametrize(
"test_type",
[
BooleanType(),
IntegerType(),
LongType(),
DateType(),
TimeType(),
TimestampType(),
TimestamptzType(),
StringType(),
UUIDType(),
FixedType(1),
BinaryType(),
],
)
def test_invalid_float_conversions(lit: Literal[Any], test_type: PrimitiveType) -> None:
with pytest.raises(TypeError):
_ = lit.to(test_type)
@pytest.mark.parametrize("lit", [literal("2017-08-18").to(DateType())])
@pytest.mark.parametrize(
"test_type",
[
BooleanType(),
IntegerType(),
LongType(),
FloatType(),
DoubleType(),
TimeType(),
TimestampType(),
TimestamptzType(),
DecimalType(9, 2),
StringType(),
UUIDType(),
FixedType(1),
BinaryType(),
],
)
def test_invalid_datetime_conversions(lit: Literal[Any], test_type: PrimitiveType) -> None:
assert_invalid_conversions(lit, [test_type])
def test_invalid_time_conversions() -> None:
assert_invalid_conversions(
literal("14:21:01.919").to(TimeType()),
[
BooleanType(),
IntegerType(),
LongType(),
FloatType(),
DoubleType(),
DateType(),
TimestampType(),
TimestamptzType(),
DecimalType(9, 2),
StringType(),
UUIDType(),
FixedType(1),
BinaryType(),
],
)
def test_invalid_timestamp_conversions() -> None:
assert_invalid_conversions(
literal("2017-08-18T14:21:01.919").to(TimestampType()),
[
BooleanType(),
IntegerType(),
LongType(),
FloatType(),
DoubleType(),
TimeType(),
DecimalType(9, 2),
StringType(),
UUIDType(),
FixedType(1),
BinaryType(),
],
)
def test_invalid_decimal_conversion_scale() -> None:
lit = literal(Decimal("34.11"))
with pytest.raises(ValueError) as e:
lit.to(DecimalType(9, 4))
assert "Could not convert 34.11 into a decimal(9, 4)" in str(e.value)
def test_invalid_decimal_conversions() -> None:
assert_invalid_conversions(
literal(Decimal("34.11")),
[
BooleanType(),
DateType(),
TimeType(),
TimestampType(),
TimestamptzType(),
StringType(),
UUIDType(),
FixedType(1),
BinaryType(),
],
)
def test_invalid_string_conversions() -> None:
assert_invalid_conversions(
literal("abc"),
[FloatType(), DoubleType(), FixedType(1), BinaryType()],
)
def test_invalid_uuid_conversions() -> None:
assert_invalid_conversions(
literal(uuid.uuid4()),
[
BooleanType(),
IntegerType(),
LongType(),
FloatType(),
DoubleType(),
DateType(),
TimeType(),
TimestampType(),
TimestamptzType(),
DecimalType(9, 2),
StringType(),
FixedType(1),
],
)
def test_invalid_fixed_conversions() -> None:
assert_invalid_conversions(
literal(bytes([0x00, 0x01, 0x02])).to(FixedType(3)),
[
BooleanType(),
IntegerType(),
LongType(),
FloatType(),
DoubleType(),
DateType(),
TimeType(),
TimestampType(),
TimestamptzType(),
DecimalType(9, 2),
StringType(),
UUIDType(),
],
)
def test_invalid_binary_conversions() -> None:
assert_invalid_conversions(
literal(bytes([0x00, 0x01, 0x02])),
[
BooleanType(),
IntegerType(),
LongType(),
FloatType(),
DoubleType(),
DateType(),
TimeType(),
TimestampType(),
TimestamptzType(),
DecimalType(9, 2),
StringType(),
UUIDType(),
],
)
def assert_invalid_conversions(lit: Literal[Any], types: List[PrimitiveType]) -> None:
for type_var in types:
with pytest.raises(TypeError):
_ = lit.to(type_var)
def test_compare_floats() -> None:
lhs = literal(18.15).to(FloatType())
rhs = literal(19.25).to(FloatType())
assert lhs != rhs
assert lhs < rhs
assert lhs <= rhs
assert not lhs > rhs
assert not lhs >= rhs
def test_string_to_int_max_value() -> None:
assert isinstance(literal(str(IntegerType.max + 1)).to(IntegerType()), IntAboveMax)
def test_string_to_int_min_value() -> None:
assert isinstance(literal(str(IntegerType.min - 1)).to(IntegerType()), IntBelowMin)
def test_string_to_integer_type_invalid_value() -> None:
with pytest.raises(ValueError) as e:
_ = literal("abc").to(IntegerType())
assert "Could not convert abc into a int" in str(e.value)
def test_string_to_long_type_invalid_value() -> None:
with pytest.raises(ValueError) as e:
_ = literal("abc").to(LongType())
assert "Could not convert abc into a long" in str(e.value)
def test_string_to_date_type_invalid_value() -> None:
with pytest.raises(ValueError) as e:
_ = literal("abc").to(DateType())
assert "Could not convert abc into a date" in str(e.value)
def test_string_to_time_type_invalid_value() -> None:
with pytest.raises(ValueError) as e:
_ = literal("abc").to(TimeType())
assert "Could not convert abc into a time" in str(e.value)
def test_string_to_decimal_type_invalid_value() -> None:
with pytest.raises(ValueError) as e:
_ = literal("18.15").to(DecimalType(10, 0))
assert "Could not convert 18.15 into a decimal(10, 0), scales differ 0 <> 2" in str(e.value)
def test_decimal_literal_increment() -> None:
dec = DecimalLiteral(Decimal("10.123"))
# Twice to check that we don't mutate the value
assert dec.increment() == DecimalLiteral(Decimal("10.124"))
assert dec.increment() == DecimalLiteral(Decimal("10.124"))
# To check that the scale is still the same
assert dec.increment().value.as_tuple() == Decimal("10.124").as_tuple()
def test_decimal_literal_dencrement() -> None:
dec = DecimalLiteral(Decimal("10.123"))
# Twice to check that we don't mutate the value
assert dec.decrement() == DecimalLiteral(Decimal("10.122"))
assert dec.decrement() == DecimalLiteral(Decimal("10.122"))
# To check that the scale is still the same
assert dec.decrement().value.as_tuple() == Decimal("10.122").as_tuple()
def test_uuid_literal_initialization() -> None:
test_uuid = uuid.UUID("f79c3e09-677c-4bbd-a479-3f349cb785e7")
uuid_literal = literal(test_uuid)
assert isinstance(uuid_literal, Literal)
assert test_uuid.bytes == uuid_literal.value
def test_uuid_to_fixed() -> None:
test_uuid = uuid.uuid4()
uuid_literal = literal(test_uuid)
fixed_literal = uuid_literal.to(FixedType(16))
assert test_uuid.bytes == fixed_literal.value
with pytest.raises(TypeError) as e:
uuid_literal.to(FixedType(15))
assert "Cannot convert UUIDLiteral into fixed[15], different length: 15 <> 16" in str(e.value)
assert isinstance(fixed_literal, FixedLiteral) # type: ignore
def test_uuid_to_binary() -> None:
test_uuid = uuid.uuid4()
uuid_literal = literal(test_uuid)
binary_literal = uuid_literal.to(BinaryType())
assert test_uuid.bytes == binary_literal.value
assert isinstance(binary_literal, BinaryLiteral) # type: ignore
# __ __ ___
# | \/ |_ _| _ \_ _
# | |\/| | || | _/ || |
# |_| |_|\_, |_| \_, |
# |__/ |__/
assert_type(literal("str"), Literal[str])
assert_type(literal(True), Literal[bool])
assert_type(literal(123), Literal[int])
assert_type(literal(123.4), Literal[float])
assert_type(literal(bytes([0x01, 0x02, 0x03])), Literal[bytes])
assert_type(literal(Decimal("19.25")), Literal[Decimal])
assert_type({literal(1), literal(2), literal(3)}, Set[Literal[int]])