Skip to content

Commit

Permalink
[AAP-9271] Add support for scientific notation (#369)
Browse files Browse the repository at this point in the history
Used generic number format to support floats and integers which supports
scientific notation.

https://issues.redhat.com/browse/AAP-9271
  • Loading branch information
mkanoor authored Feb 15, 2023
2 parents fa9ecd1 + 3610f48 commit 3e0d9ff
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 31 deletions.
20 changes: 6 additions & 14 deletions ansible_rulebook/condition_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,15 @@
from ansible_rulebook.condition_types import ( # noqa: E402
Boolean,
Condition,
Float,
Identifier,
Integer,
KeywordValue,
NegateExpression,
OperatorExpression,
SearchType,
SelectattrType,
SelectType,
String,
to_condition_type,
)

VALID_SELECT_ATTR_OPERATORS = [
Expand Down Expand Up @@ -85,12 +84,8 @@

logger = logging.getLogger(__name__)

integer = pyparsing_common.signed_integer.copy().add_parse_action(
lambda toks: Integer(toks[0])
)

float_t = pyparsing_common.real.copy().add_parse_action(
lambda toks: Float(toks[0])
number_t = pyparsing_common.number.copy().add_parse_action(
lambda toks: to_condition_type(toks[0])
)

ident = pyparsing_common.identifier
Expand All @@ -115,7 +110,7 @@
QuotedString('"').copy().add_parse_action(lambda toks: String(toks[0]))
)

allowed_values = float_t | integer | boolean | string1 | string2
allowed_values = number_t | boolean | string1 | string2
key_value = ident + Suppress("=") + allowed_values
string_search_t = (
one_of("regex match search")
Expand All @@ -124,9 +119,7 @@
+ Suppress(")")
)

delim_value = Group(
delimitedList(float_t | integer | ident | string1 | string2)
)
delim_value = Group(delimitedList(number_t | ident | string1 | string2))
list_values = Suppress("[") + delim_value + Suppress("]")

selectattr_t = (
Expand Down Expand Up @@ -217,8 +210,7 @@ def OperatorExpressionFactory(tokens):
| select_t
| string_search_t
| list_values
| float_t
| integer
| number_t
| boolean
| varname
| string1
Expand Down
17 changes: 17 additions & 0 deletions ansible_rulebook/condition_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

from typing import List, NamedTuple, Union

from .exception import InvalidTypeException


class Integer(NamedTuple):
value: int
Expand Down Expand Up @@ -97,3 +99,18 @@ class Condition(NamedTuple):
SelectType,
SelectattrType,
]


def to_condition_type(value):
if isinstance(value, int):
return Integer(value)
elif isinstance(value, bool):
return Boolean(value)
elif isinstance(value, str):
return String(value)
elif isinstance(value, float):
return Float(value)
elif isinstance(value, list):
return [to_condition_type(v) for v in value]
else:
raise InvalidTypeException(f"Invalid type for {value}")
5 changes: 5 additions & 0 deletions ansible_rulebook/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,8 @@ class SelectOperatorException(Exception):
class ConditionParsingException(Exception):

pass


class InvalidTypeException(Exception):

pass
20 changes: 4 additions & 16 deletions ansible_rulebook/json_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
SelectattrType,
SelectType,
String,
to_condition_type,
)
from ansible_rulebook.exception import (
InvalidAssignmentException,
Expand Down Expand Up @@ -92,7 +93,9 @@ def visit_condition(parsed_condition: ConditionTypes, variables: Dict):
key = parsed_condition.value[5:]
try:
return visit_condition(
convert_to_type(dpath.get(variables, key, separator=".")),
to_condition_type(
dpath.get(variables, key, separator=".")
),
variables,
)
except KeyError:
Expand Down Expand Up @@ -202,21 +205,6 @@ def visit_condition(parsed_condition: ConditionTypes, variables: Dict):
raise Exception(f"Unhandled token {parsed_condition}")


def convert_to_type(value):
if isinstance(value, int):
return Integer(value)
elif isinstance(value, bool):
return Boolean(value)
elif isinstance(value, str):
return String(value)
elif isinstance(value, float):
return Float(value)
elif isinstance(value, list):
return [convert_to_type(v) for v in value]
else:
raise Exception(f"Invalid type for {value}")


def create_binary_node(name, parsed_condition, variables):
return {
name: {
Expand Down
5 changes: 5 additions & 0 deletions tests/examples/49_float.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
payload:
- pi: 3.14159
- mass: 5.97219
- radius: 300.42
rules:
- name: r1
condition: event.pi == 3.14159
Expand All @@ -16,3 +17,7 @@
condition: event.mass in [3.14159, 5.97219]
action:
debug:
- name: r3
condition: event.radius > 2.12345e+2
action:
debug:
6 changes: 5 additions & 1 deletion tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,11 @@ async def test_49_float():
assert event["action"] == "debug", "4"
assert event["matching_events"] == {"m": {"mass": 5.97219}}, "5"
event = event_log.get_nowait()
assert event["type"] == "Shutdown", "7"
assert event["type"] == "Action", "6"
assert event["action"] == "debug", "7"
assert event["matching_events"] == {"m": {"radius": 300.42}}, "8"
event = event_log.get_nowait()
assert event["type"] == "Shutdown", "9"


@pytest.mark.asyncio
Expand Down

0 comments on commit 3e0d9ff

Please sign in to comment.