zeroSteiner / rule-engine

A lightweight, optionally typed expression language with a custom grammar for matching arbitrary Python objects.
https://zerosteiner.github.io/rule-engine/
BSD 3-Clause "New" or "Revised" License
445 stars 54 forks source link

None type arithmetic checks do not work if a type resolver is provided #14

Closed 53A-1 closed 3 years ago

53A-1 commented 3 years ago

The workarounds given in https://github.com/zeroSteiner/rule-engine/issues/13 do not work in case the types are provided:

con = rule_engine.Context(
            type_resolver=rule_engine.type_resolver_from_dict(
                {
                    "TEST_FLOAT": rule_engine.DataType.FLOAT,
                }
            ),
            default_value=None,
        )
        rul = rule_engine.Rule(
            # "TEST_FLOAT != null and TEST_FLOAT < 42",
            "(TEST_FLOAT == null ? 0 : TEST_FLOAT) < 42",
            context=con,
        )
        test = rul.matches({"TEST_FLOAT": None})

This will produce an errors.EvaluationError('data type mismatch') Wouldn't it make sense to add a check whether any side is None to __op_arithmetic_values, i.e. a

elif left_value is None or right_value is None:
    return False

right after checking if both are None?

Working around this in Python by normalizing the input value is not an elegant option since it would require to typedef the values twice - once for the Rule Engine context and once for the normalization.

EDIT: Ok, worked around it using rule.condition.context.resolve_type(mapping) == rule_engine.DataType.FLOAT now, but it still seems adding the check to the library would make this task easier, albeit arithmetic operators are undefined for None.

zeroSteiner commented 3 years ago

Yeah this looks like a bug. Thanks for reporting it, I'll look into it and see if I can get a solution in place.

zeroSteiner commented 3 years ago

Fixed in commit 5ca2c84d3ee63488ac31e6c524064de3f35aa72b. This was an issue due to a data type compatibility check within the equals and not-equals operators of the ast.ComparisonExpression class. The equality operators should be able to work with any combination of data types.

The reason this worked when there was no type information is that the type would default to UNDEFINED which is considered to be compatible with anything.

Once the unit tests pass, I'll tag and release v3.1.1. Again thanks for reporting this.

zeroSteiner commented 3 years ago

Fixed in release 3.1.1 which is now on PyPi.

53A-1 commented 3 years ago

Great, thanks a million for the quick fix and rollout to PyPi!