diff --git a/python/examples/ingestion_with_python_config/telemetry_config.py b/python/examples/ingestion_with_python_config/telemetry_config.py index 1c4a3904e..62c16b816 100644 --- a/python/examples/ingestion_with_python_config/telemetry_config.py +++ b/python/examples/ingestion_with_python_config/telemetry_config.py @@ -1,5 +1,3 @@ -from pathlib import Path - from sift_py.ingestion.channel import ( ChannelBitFieldElement, ChannelConfig, @@ -12,8 +10,6 @@ RuleConfig, ) -RULE_NAMESPACES_DIR = Path().joinpath("rule_modules") - def nostromos_lv_426() -> TelemetryConfig: log_channel = ChannelConfig( @@ -85,6 +81,7 @@ def nostromos_lv_426() -> TelemetryConfig: FlowConfig(name="logs", channels=[log_channel]), ], rules=[ + # Add `is_live=True` if you want these rules to run on live data. RuleConfig( name="overheating", description="Checks for vehicle overheating", diff --git a/python/examples/ingestion_with_yaml_config/rule_modules/nostromo.yml b/python/examples/ingestion_with_yaml_config/rule_modules/nostromo.yml index 0ad84e144..30b0468f7 100644 --- a/python/examples/ingestion_with_yaml_config/rule_modules/nostromo.yml +++ b/python/examples/ingestion_with_yaml_config/rule_modules/nostromo.yml @@ -1,3 +1,5 @@ +# Example rules configs. Add 'is_live' if you want these rules to run on live data. + rules: - name: overheating description: Checks for vehicle overheating diff --git a/python/examples/ingestion_with_yaml_config/rule_modules/velocity.yml b/python/examples/ingestion_with_yaml_config/rule_modules/velocity.yml index 968c8132c..e0139af9c 100644 --- a/python/examples/ingestion_with_yaml_config/rule_modules/velocity.yml +++ b/python/examples/ingestion_with_yaml_config/rule_modules/velocity.yml @@ -1,3 +1,5 @@ +# Example rules configs. Add 'is_live: true' if you want these rules to run on live data. + rules: - name: vehicle_stuck description: Triggers if the vehicle velocity is not 0 for 5s after entering accelerating state diff --git a/python/examples/ingestion_with_yaml_config/rule_modules/voltage.yml b/python/examples/ingestion_with_yaml_config/rule_modules/voltage.yml index dd9da4d4f..6d8ce5e58 100644 --- a/python/examples/ingestion_with_yaml_config/rule_modules/voltage.yml +++ b/python/examples/ingestion_with_yaml_config/rule_modules/voltage.yml @@ -1,3 +1,4 @@ +# Example rules configs. Add 'is_live: true' if you want these rules to run on live data. rules: - name: overvoltage description: Checks for overvoltage while accelerating diff --git a/python/lib/sift_py/rule/config.py b/python/lib/sift_py/rule/config.py index 3b38e3f48..748405d4f 100644 --- a/python/lib/sift_py/rule/config.py +++ b/python/lib/sift_py/rule/config.py @@ -27,6 +27,8 @@ class RuleConfig(AsJson): - `tag_names`: A list of asset names that this rule should be applied to. ONLY VALID if defining rules outside of a telemetry config. - `contextual_channels`: A list of channel names that provide context but aren't directly used in the expression. - `is_external`: If this is an external rule. + - `is_live`: If set to True then this rule will be evaluated on live data, otherwise live rule evaluation will be disabled. + This rule can still be used, however, in report generation. """ name: str @@ -38,6 +40,7 @@ class RuleConfig(AsJson): asset_names: List[str] contextual_channels: List[str] is_external: bool + is_live: bool _rule_id: Optional[str] # Allow passing of rule_id when existing config retrieved from API def __init__( @@ -55,6 +58,7 @@ def __init__( sub_expressions: Dict[str, Any] = {}, contextual_channels: Optional[List[str]] = None, is_external: bool = False, + is_live: bool = False, ): self.channel_references = _channel_references_from_dicts(channel_references) self.contextual_channels = contextual_channels or [] @@ -66,6 +70,7 @@ def __init__( self.description = description self.expression = self.__class__.interpolate_sub_expressions(expression, sub_expressions) self.is_external = is_external + self.is_live = is_live self._rule_id = None def as_json(self) -> Any: @@ -83,6 +88,7 @@ def as_json(self) -> Any: "description": self.description, "expression": self.expression, "is_external": self.is_external, + "is_live": self.is_live, } hash_map["expression_channel_references"] = self.channel_references diff --git a/python/lib/sift_py/rule/service.py b/python/lib/sift_py/rule/service.py index 1b7f0f425..db2951725 100644 --- a/python/lib/sift_py/rule/service.py +++ b/python/lib/sift_py/rule/service.py @@ -98,6 +98,7 @@ def create_external_rules_from_yaml( """ Creates external rules from a YAML spec in the Sift API. For more on rule YAML definitions, see `sift_py.ingestion.config.yaml.spec.RuleYamlSpec`. + If is_external is set in the YAML, this overrides that. Args: paths: The list of YAML paths to load. @@ -229,6 +230,8 @@ def _parse_rules_from_yaml( contextual_channels=contextual_channels, asset_names=rule_yaml.get("asset_names", []), sub_expressions=subexpr, + is_external=rule_yaml.get("is_external", False), + is_live=rule_yaml.get("is_live", False), ) ) @@ -510,6 +513,7 @@ def _update_req_from_rule_config( ), contextual_channels=ContextualChannels(channels=contextual_channel_names), is_external=config.is_external, + is_live_evaluation_enabled=config.is_live, ) def get_rule(self, rule: str) -> Optional[RuleConfig]: diff --git a/python/lib/sift_py/yaml/rule.py b/python/lib/sift_py/yaml/rule.py index abb05d965..e2220eb9b 100644 --- a/python/lib/sift_py/yaml/rule.py +++ b/python/lib/sift_py/yaml/rule.py @@ -270,6 +270,9 @@ class RuleYamlSpec(TypedDict): `sub_expressions`: A list of sub-expressions which is a mapping of place-holders to sub-expressions. Only used if using named expressions. `asset_names`: A list of asset names that this rule should be applied to. ONLY VALID if defining rules outside of a telemetry config. `tag_names`: A list of tag names that this rule should be applied to. ONLY VALID if defining rules outside of a telemetry config. + `is_external`: If this is an external rule. + `is_live`: If set to True then this rule will be evaluated on live data, otherwise live rule evaluation will be disabled. + This rule can still be used, however, in report generation. Channel references: A channel reference is a string containing a numerical value prefixed with "$". Examples include "$1", "$2", "$11", and so on. @@ -326,6 +329,8 @@ class RuleYamlSpec(TypedDict): sub_expressions: NotRequired[List[Dict[str, str]]] asset_names: NotRequired[List[str]] tag_names: NotRequired[List[str]] + is_external: NotRequired[bool] + is_live: NotRequired[bool] class NamedExpressionYamlSpec(TypedDict):