{"id":45525991,"url":"https://github.com/saurabh0719/py-rules-engine","last_synced_at":"2026-02-22T23:48:52.042Z","repository":{"id":212376724,"uuid":"731056238","full_name":"saurabh0719/py-rules-engine","owner":"saurabh0719","description":"A pure-python rules engine. Packed with components to build rules and a rule parser. :arrow_forward:","archived":false,"fork":false,"pushed_at":"2024-02-29T05:18:23.000Z","size":89,"stargazers_count":30,"open_issues_count":3,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-25T17:14:38.164Z","etag":null,"topics":["rule-engine","rules","rules-engine"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/py-rules-engine/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saurabh0719.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-12-13T09:07:20.000Z","updated_at":"2025-08-06T02:47:49.000Z","dependencies_parsed_at":"2023-12-13T23:32:27.936Z","dependency_job_id":"d269a6d4-36d5-44f4-9efd-649fb935dad2","html_url":"https://github.com/saurabh0719/py-rules-engine","commit_stats":null,"previous_names":["saurabh0719/py-rules-engine","saurabh0719/py-rules"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/saurabh0719/py-rules-engine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saurabh0719%2Fpy-rules-engine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saurabh0719%2Fpy-rules-engine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saurabh0719%2Fpy-rules-engine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saurabh0719%2Fpy-rules-engine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saurabh0719","download_url":"https://codeload.github.com/saurabh0719/py-rules-engine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saurabh0719%2Fpy-rules-engine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29731239,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T20:09:16.275Z","status":"ssl_error","status_checked_at":"2026-02-22T20:09:13.750Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rule-engine","rules","rules-engine"],"created_at":"2026-02-22T23:48:49.615Z","updated_at":"2026-02-22T23:48:52.028Z","avatar_url":"https://github.com/saurabh0719.png","language":"Python","readme":"\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"800\" src=\"https://github.com/saurabh0719/py-rules-engine/assets/42310348/976bbd30-8725-476b-8502-1a29c7fc8683\"\u003e\n\u003c/p\u003e\n\n\n`py-rules-engine` is a robust, Python-based rules engine that enables the creation of intricate logical conditions and actions. \n\n```bash\npip install py-rules-engine\n```\n\n\nKey features:\n\n- **Complex Logical Conditions**: Define intricate conditions using logical operators.\n- **Pythonic Rule Builder**: Utilize a Pythonic interface for easy rule definition.\n- **Flexible Rule Management**: Store, configure, and share rules in JSON/YAML format, with seamless shifting between Python rule builder and other formats.\n- **Nested Rules**: Create multi-level rule structures.\n- **Rule Evaluation**: Evaluate rules in a given context with a built-in rule engine.\n- **Zero Dependencies**: Pure Python implementation for easy installation and use.\n\n\nExample usage -\n\n\n```python\n\nfrom py_rules.components import Condition, Result, Rule\nfrom py_rules.engine import RuleEngine\n\n# Create a condition\ncondition = Condition('temperature', '\u003e=', 40) | Condition('wind_speed', '\u003e', 50)\n\n# Create a result\nresult = Result('message', 'str', 'Unfavourable weather conditions for work!')\n\n# Create a rule\nrule = Rule('Temperature Rule').If(condition).Then(result)\n\n# initialise a new instance of RuleEngine with context\ncontext = {'temperature': 45, 'wind_speed': 30}\nengine = RuleEngine(context)\n\nprint(engine.evaluate(rule))\n# 'Unfavourable weather conditions for work!'\n\n# if a Rule is used without a Result, it simply returns True/False\nrule = Rule('Bool Temperature Rule').If(condition)\nprint(engine.evaluate(rule))\n# True\n\n```\n\n\u003cspan id=\"table-of-contents\"\u003e\u003c/span\u003e\n\n## Table of Contents :\n* [Installation](#installation)\n* [Rule structure](#structure)\n  * [Basics](#basics)\n  * [Representation](#repr)\n* [Rule builder \u0026 parser](#builder)\n  * [Components](#components)\n  * [Nested rules](#nested)\n  * [Parser](#parser)\n* [Rule engine and evaluation](#engine)\n* [Rule storage and parsing](#storage)\n* [Tests](#tests)\n* [To do](#todo)\n\n\n\u003cspan id=\"installation\"\u003e\u003c/span\u003e\n\n## Installation\nYou can install `py-rules-engine` using pip:\n\n```bash\npip install py-rules-engine\n```\n\n**NOTE** - this library is currently in Beta, and things may break between version bumps pre-1.0.0.\n\n\n\u003cspan id=\"structure\"\u003e\u003c/span\u003e\n\n## Rule structure\n\nThis section covers the basics of this library, including the structure of the `Rule` object.\n\n\u003cspan id=\"basics\"\u003e\u003c/span\u003e\n\n### Basics\n\nThe `If-Then-Else` structure is a fundamental part of the rule engine. It allows you to define a condition and specify the results based on whether the condition is met or not. Here's a breakdown of each part:\n\n- `If`: This is the condition that will be evaluated. It can be a simple condition (like \"temperature \u003e 30\") or a complex condition involving multiple variables and logical operators (like \"temperature \u003e 30 AND humidity \u003c 50\"). The condition is evaluated against a given `context`, which is a dictionary of variables and their values.\n\n- `Then`: This part specifies the result or action that should be returned or performed if the IF condition is met (i.e., if it evaluates to True). It can be a simple value (like \"It's hot\") or a complex object. It can also be another `Rule`, allowing for `nested rules`.\n\n- `Else`: This part specifies the result or action that should be returned or performed if the IF condition is not met (i.e., if it evaluates to False). Like the THEN part, it can be a simple value, a complex object, or another `Rule`. The ELSE part is optional; if it's not provided and the IF condition is not met, the rule engine will return False.\n\n\nEvery `Rule` object's `dict` representation (rule.to_dict()) contains the following\n\n- `metadata`: This section contains metadata about the rule.\n\n  - `version`: The version of the rule.\n  - `id`: A unique identifier for the rule.\n  - `parent_id`: The id of the parent rule if this rule is nested, otherwise null.\n  - `created`: The UTC timestamp when the rule was created.\n  - `name`: The name of the rule.\n  - `required_context_parameters`: A list of context parameters that are required for this rule. These variables/parameters are passed to the `RuleEngine` via a `context` dictionary\n\n- `if`: This section contains the condition to be evaluated.\n\n  - `condition` or `and` or `or`: The condition to be evaluated. It can be a single condition or a logical combination (`and`, `or`) of multiple conditions. Each condition consists of a `variable`, an `operator`, and a `value`.\n\n- `then`: This section contains the result to be returned if the `if` condition evaluates to `True`.\n\n- `else`: This section contains the result to be returned if the `if` condition evaluates to `False`, or a nested rule with its own `if`, `then`, and `else` sections.\n\nAll the `Rule`(s) are evaluated against a `context` dictionary. The `context` is key-value dictionary of `facts` we use to evaluate all conditions and prepare return statements.\n\nSee the `examples/` directory for more.\n\n[Go back to top](#table-of-contents)\n\u003cbr\u003e\n\n\u003cspan id=\"repr\"\u003e\u003c/span\u003e\n\n### Representation\n\nEvery `Rule` object and it's conditions is represented as a `dictionary` structure. Ev\n\nFor example-\n\n```python\n\nfrom py_rules.components import Condition, Result, Rule\nfrom py_rules.engine import RuleEngine\n\n# Create a condition\ncondition = Condition('temperature', '\u003e', 40) | Condition('wind_speed', '\u003e', 50)\nno_work = Result('message', 'str', 'Unfavourable weather conditions for work!')\nwork = Result('message', 'str', 'Favourable weather conditions for work!')\nrule = Rule('Temperature Rule').If(condition).Then(no_work).Else(work)\n\nprint(rule.to_dict())\n\n\"\"\"\n{\n    \"metadata\": {\n        \"version\": \"0.3.0\",\n        \"type\": \"Rule\",\n        \"id\": \"a605f337-7d60-4a65-a361-96c282e3fc74\",\n        \"created\": \"2023-12-15 12:53:48.492187\",\n        \"required_context_parameters\": [\"wind_speed\", \"temperature\"],\n        \"name\": \"Temperature Rule\",\n        \"parent_id\": None,\n    },\n    \"if\": {\n        \"or\": [\n            {\n                \"condition\": {\n                    \"metadata\": {\n                        \"version\": \"0.3.0\",\n                        \"type\": \"Condition\",\n                        \"id\": \"10346a0c-3934-4ed9-b393-053b871ab17d\",\n                        \"created\": \"2023-12-15 12:53:48.492090\",\n                        \"required_context_parameters\": [\"temperature\"],\n                    },\n                    \"variable\": \"temperature\",\n                    \"operator\": \"\u003e\",\n                    \"value\": {\"type\": \"int\", \"value\": 40},\n                }\n            },\n            {\n                \"condition\": {\n                    \"metadata\": {\n                        \"version\": \"0.3.0\",\n                        \"type\": \"Condition\",\n                        \"id\": \"0f3e660e-01a6-41d1-849c-e5b27088ccb4\",\n                        \"created\": \"2023-12-15 12:53:48.492140\",\n                        \"required_context_parameters\": [\"wind_speed\"],\n                    },\n                    \"variable\": \"wind_speed\",\n                    \"operator\": \"\u003e\",\n                    \"value\": {\"type\": \"int\", \"value\": 50},\n                }\n            },\n        ]\n    },\n    \"then\": {\n        \"result\": {\n            \"message\": {\n                \"type\": \"str\",\n                \"value\": \"Unfavourable weather conditions for work!\",\n            }\n        }\n    },\n    \"else\": {\n        \"result\": {\n            \"message\": {\n                \"type\": \"str\",\n                \"value\": \"Favourable weather conditions for work!\",\n            }\n        }\n    },\n}\n\"\"\"\n\n```\n\nThis `dictionary` is what is used for evaluation.\n\n\n[Go back to top](#table-of-contents)\n\u003cbr\u003e\n\n\u003cspan id=\"builder\"\u003e\u003c/span\u003e\n\n## Rule builder \u0026 parser\n\n\n\u003cspan id=\"components\"\u003e\u003c/span\u003e\n\n### Rule components\n\nThe following components can be used to build complex Rules.\n\n- `Condition`: This class represents a condition in a rule. It can be initialized with a variable, operator, and value, or with a condition dictionary. It supports logical `and` and `or` operations to combine conditions. The `to_dict` method returns a dictionary representation of the condition.\n\n- `Result`: This class represents a result in a Rule. It can be initialized with a key, type, and value, or with a result dictionary. It supports the `and` operation to combine results. The `to_dict` method returns a dictionary representation of the result.\n\n- `Rule`: This class represents a rule. It can be initialized with a name and optional keyword arguments. It supports the `If`, `Then`, and `Else` methods to set the condition and results of the rule. The `to_dict` method returns a dictionary representation of the rule.\n\n\n```python\n\nfrom py_rules.components import Condition, Result, Rule\n\n# Create a condition\ncondition = Condition('temperature', '\u003e', 30)\n\n# Create a result\nresult = Result('message', 'str', 'It is hot!')\n\n# Create a rule\nrule = Rule('Temperature Rule').If(condition).Then(result)\n\n# Print the rule\nprint(rule.to_dict())\n\n```\n\nOutput -\n\n```python\n\n{\n    \"metadata\": {\n        \"version\": \"0.3.0\",\n        \"type\": \"Rule\",\n        \"id\": \"5dbca846-5e59-4b6c-bdbf-9602d68c79ff\",\n        \"created\": \"2023-12-15 04:49:45.183531\",\n        \"required_context_parameters\": [\"temperature\"],\n        \"name\": \"Temperature Rule\",\n        \"parent_id\": None,\n    },\n    \"if\": {\n        \"condition\": {\n            \"metadata\": {\n                \"version\": \"0.3.0\",\n                \"type\": \"Condition\",\n                \"id\": \"14950c65-3741-40da-ac13-e5cf1a0c49ce\",\n                \"created\": \"2023-12-15 04:49:45.183438\",\n                \"required_context_parameters\": [\"temperature\"],\n            },\n            \"variable\": \"temperature\",\n            \"operator\": \"\u003e\",\n            \"value\": {\"type\": \"int\", \"value\": 30},\n        }\n    },\n    \"then\": {\"result\": {\"message\": {\"type\": \"str\", \"value\": \"It is hot!\"}}},\n}\n\n```\n\nThis will create a rule that checks if the temperature is greater than 30 and returns the message \"It is hot!\" if the condition is met.\n\n\u003cspan id='nested'\u003e\u003c/span\u003e\n\n### Nested rules -\n\n```python\n\nfrom py_rules.components import Condition, Result, Rule\n\n# Create conditions\ncondition1 = Condition('temperature', '\u003e', 30)\ncondition2 = Condition('humidity', '\u003c', 50)\n\n# Create results\nresult1 = Result('message', 'str', 'It is hot!')\nresult2 = Result('message', 'str', 'It is dry!')\n\n# Create rules\nrule1 = Rule('Temperature Rule').If(condition1).Then(result1)\nrule2 = Rule('Humidity Rule').If(condition2).Then(result2)\n\n# Create a nested rule\nnested_rule = Rule('Nested Rule').If(condition1).Then(rule2).Else(result1)\n\n# Print the nested rule\nprint(nested_rule.to_dict())\n\n```\n\nThis will create a nested rule that checks if the temperature is greater than 30. If the condition is met, it evaluates another rule that checks if the humidity is less than 50. If the nested condition is met, it returns the message \"It is dry!\". If the nested condition is not met, it returns the message \"It is hot!\".\n\nHere's the equivalent rule in JSON format:\n\n```json\n{\n    \"metadata\": {\n        \"version\": \"0.3.0\",\n        \"type\": \"Rule\",\n        \"id\": \"7f2a4893-322c-4973-8e41-c3930e37648b\",\n        \"created\": \"2023-12-15 04:57:33.071026\",\n        \"required_context_parameters\": [\"temperature\", \"humidity\"],\n        \"name\": \"Nested Rule\",\n        \"parent_id\": null,\n    },\n    \"if\": {\n        \"condition\": {\n            \"metadata\": {\n                \"version\": \"0.3.0\",\n                \"type\": \"Condition\",\n                \"id\": \"515a3a0e-6a45-4848-9ea9-8202e66372cf\",\n                \"created\": \"2023-12-15 04:57:33.070916\",\n                \"required_context_parameters\": [\"temperature\"],\n            },\n            \"variable\": \"temperature\",\n            \"operator\": \"\u003e\",\n            \"value\": {\"type\": \"int\", \"value\": 30},\n        }\n    },\n    \"then\": {\n        \"metadata\": {\n            \"version\": \"0.3.0\",\n            \"type\": \"Rule\",\n            \"id\": \"7c045ec9-c262-4c6c-8b0f-34cc773d4f41\",\n            \"created\": \"2023-12-15 04:57:33.071017\",\n            \"required_context_parameters\": [\"humidity\"],\n            \"name\": \"Humidity Rule\",\n            \"parent_id\": null,\n        },\n        \"if\": {\n            \"condition\": {\n                \"metadata\": {\n                    \"version\": \"0.3.0\",\n                    \"type\": \"Condition\",\n                    \"id\": \"ddc1e0f2-54a5-4c4f-aedd-2f6db69741dc\",\n                    \"created\": \"2023-12-15 04:57:33.070964\",\n                    \"required_context_parameters\": [\"humidity\"],\n                },\n                \"variable\": \"humidity\",\n                \"operator\": \"\u003c\",\n                \"value\": {\"type\": \"int\", \"value\": 50},\n            }\n        },\n        \"then\": {\"result\": {\"message\": {\"type\": \"str\", \"value\": \"It is dry!\"}}},\n    },\n    \"else\": {\"result\": {\"message\": {\"type\": \"str\", \"value\": \"It is hot!\"}}},\n}\n\n```\n\n[Go back to top](#table-of-contents)\n\u003cbr\u003e\n\n\n\u003cspan id=\"parser\"\u003e\u003c/span\u003e\n\n### Rule Parser\n\nThe `RuleParser` class is a utility class that is used to parse a rule from a `python dictionary` into a `Rule` object. This is useful when you want to define rules in a another format (JSON, YAML, etc.) and then load them into your Python code.\n\n```python\n\nfrom py_rules.components import Rule\nfrom py_rules.parser import RuleParser\n\n# Define a rule as a dictionary\nrule_dict = {\n    \"metadata\": {\n        \"version\": \"0.3.0\",\n        \"type\": \"Rule\",\n        \"id\": \"9911bf90-b6a1-490f-ae5a-3fa9409529f8\",\n        \"created\": \"2023-12-15 13:09:59.411292\",\n        \"required_context_parameters\": [\"temperature\"],\n        \"name\": \"Unnamed Rule 1\",\n        \"parent_id\": None,\n    },\n    \"if\": {\n        \"condition\": {\n            \"metadata\": {\n                \"version\": \"0.3.0\",\n                \"type\": \"Condition\",\n                \"id\": \"a4b678f7-44f3-4818-8a72-298880263703\",\n                \"created\": \"2023-12-15 13:09:59.411350\",\n                \"required_context_parameters\": [\"temperature\"],\n            },\n            \"variable\": \"temperature\",\n            \"operator\": \"\u003e\",\n            \"value\": {\"type\": \"int\", \"value\": 30},\n        }\n    },\n    \"then\": {\"result\": {\"message\": {\"type\": \"str\", \"value\": \"It's hot\"}}},\n    \"else\": {\"result\": {\"message\": {\"type\": \"str\", \"value\": \"It's not hot\"}}},\n}\n\n\n# Parse the rule\nrule = RuleParser().parse(rule_dict)\n\nprint(type(rule))\n# \u003cclass 'py_rules.components.Rule'\u003e\n\nassert isinstance(rule, Rule)\n\nprint(rule.metadata)\n# {'version': '0.3.0', 'type': 'Rule', 'id': '9911bf90-b6a1-490f-ae5a-3fa9409529f8', 'created': '2023-12-15 13:09:59.411292', 'required_context_parameters': ['temperature'], 'name': 'Unnamed Rule 1', 'parent_id': None}\n\n```\n\n[Go back to top](#table-of-contents)\n\u003cbr\u003e\n\n\n\u003cspan id=\"engine\"\u003e\u003c/span\u003e\n\n## Rule engine and evaluation\n\nThe `RuleEngine` class is used to evaluate a rules. It takes a `Rule` object and a context (a dictionary) as input. The `Rule` is then evaluated against the `context`\n\nHere's a breakdown of the methods in the RuleEngine class:\n\n- `__init__`: Initializes the RuleEngine with a `context: dict`; a dictionary of `facts`.\n\n    - The `context` dictionary MUST contain all the `variable`(s) being used, either in results or in conditions. The `required_context_parameters` set() of the `Rule` maintains a list of all unique context parameters required to evaluate the rule.\n\n- `evaluate(rule: Rule)`: Evaluates the rule. It checks the 'if' condition and returns the result of the 'then' action if the condition is met, or the result of the 'else' action otherwise.\n\nHere's an example of how to use the RuleEngine class:\n\n```python\n\nfrom py_rules.builder import Condition, Result, Rule\nfrom py_rules.engine import RuleEngine\n\n# Create a condition\ncondition = Condition('temperature', '\u003e', 30)\n\n# Create a result\nresult = Result('message', 'str', 'It is hot!')\n\n# Create a rule\nrule = Rule('Temperature Rule').If(condition).Then(result)\n\n# Create a context\ncontext = {'temperature': 35}\n\n# Create a rule engine\nengine = RuleEngine(context)\n\n# Evaluate the rule\nprint(engine.evaluate(rule))  # prints: {'message': 'It is hot!'}\n\n```\n\nIn this example, the rule checks if the temperature is greater than 30. The context provides the actual temperature. The rule engine evaluates the rule in the given context and returns the result of the rule.\n\nYou can also use the `RuleEngine` class with complex rules that have nested conditions and multiple results. Here's an example:\n\n```python\n\n# Create conditions\ncondition1 = Condition('temperature', '\u003e', 30)\ncondition2 = Condition('humidity', '\u003c', 50)\n\n# Create results\nresult1 = Result('message', 'str', 'It is hot!')\nresult2 = Result('message', 'str', 'It is dry!')\n\n# Create rules\nrule1 = Rule('Temperature Rule').If(condition1).Then(result1)\nrule2 = Rule('Humidity Rule').If(condition2).Then(result2)\n\n# Create a context\ncontext = {'temperature': 35, 'humidity': 45}\n\n# Create a rule engine\nengine = RuleEngine(context)\n\n# Evaluate the rules\nprint(engine.evaluate(rule1))  # prints: {'message': 'It is hot!'}\nprint(engine.evaluate(rule2))  # prints: {'message': 'It is dry!'}\n\n```\n\nIn this example, the first rule checks if the temperature is greater than 30, and the second rule checks if the humidity is less than 50. The context provides the actual temperature and humidity. The rule engines evaluate the rules in the given context and return the results of the rules.\n\n[Go back to top](#table-of-contents)\n\u003cbr\u003e\n\n\u003cspan id=\"storage\"\u003e\u003c/span\u003e\n\n## Rule parsing and storage\n\nStoring \u0026 loading rules from persistent storage enable reuse of rules across different sessions and sharing of rules between different systems.\n\nThe `RuleStorage` class is an abstract base class that defines the common interface for all storage classes. It has two abstract methods: `load` and `store`. Any class that inherits from `RuleStorage` must implement these methods. The `RuleStorage` class also has a RuleParser object that is used to parse a rule **after it is loaded into a `dictionary`** format.\n\nThe `JSONRuleStorage` and `PickledRuleStorage` classes are concrete classes that inherit from RuleStorage and implement the load and store methods. Each class is designed to work with a specific file format.\n\nEach class also validates the file type in its constructor to ensure that it matches the expected file type. If the file type is not valid, it raises an `InvalidRuleError`.\n\nYou can also create your own `RuleStorage` class, as shown in the example below for `yaml` files -\n\n```python\nimport yaml\n\nfrom py_rules.components import Condition, Result, Rule\nfrom py_rules.storages import RuleStorage, JSONRuleStorage, PickledRuleStorage\n\nyaml.Dumper.ignore_aliases = lambda *args: True\n\n# CUSTOM Yaml Storage\nclass YAMLRuleStorage(RuleStorage):\n    \"\"\"\n    RuleStorage class for YAML files.\n    \"\"\"\n\n    format = 'yaml'\n\n    def __init__(self, file_path):\n        \"\"\"\n        Initialize the loader with a file_path.\n        \"\"\"\n        super().__init__()\n        self.file_path = file_path\n        # validate that the file_path is valid and is a yaml file\n        if not self.file_path.endswith('.yaml'):\n            raise InvalidRuleError('Invalid file type. Only YAML files are supported.')\n\n    def load(self):\n        \"\"\"\n        Load a rule from a YAML file.\n        \"\"\"\n        data = {}\n        with open(self.file_path) as f:\n            data = yaml.load(f, Loader=yaml.FullLoader)\n        return self.parser.parse(data)\n\n    def store(self, rule):\n        \"\"\"\n        Store a rule in a YAML file.\n        \"\"\"\n        data = rule.to_dict()\n        with open(self.file_path, 'w') as f:\n            yaml.dump(data, f, default_flow_style=False, indent=4, sort_keys=False)\n\n\n# Define conditions\ncondition1 = Condition('number', 'in', [1, 2, 3])\ncondition2 = Condition('number', '=', 1)\n\n# Combine conditions using logical 'and'\ncombined_condition = condition1 \u0026 condition2\n\n# Define results\nresult1 = Result('xyz', 'str', 'Condition met')\nresult2 = Result('result', 'variable', 'xyz')\n\n# Combine results using logical 'and'\ncombined_result = result1 \u0026 result2\n\n# Define a nested rule\nnested_rule = Rule('Nested rule').If(condition1).Then(result1)\n\n# Define a complex rule with nested conditions and rules\ncomplex_rule = Rule('Complex rule').If(combined_condition).Then(combined_result).Else(nested_rule)\n\n# Store the complex rule in different formats\nJSONRuleStorage('rule.json').store(complex_rule)\nYAMLRuleStorage('rule.yaml').store(complex_rule)\n\n# Load the complex rule from each format\njson_rule = JSONRuleStorage('rule.json').load()\nyaml_rule = YAMLRuleStorage('rule.yaml').load()\n\nassert complex_rule == json_rule == yaml_rule\n\n```\n\n\n`rule.json` -\n\n```json\n\n{\n    \"metadata\": {\n        \"version\": \"0.3.0\",\n        \"type\": \"Rule\",\n        \"id\": \"8330dd39-a0a4-4f21-aab4-0f8e35924c74\",\n        \"created\": \"2023-12-15 04:54:00.349206\",\n        \"required_context_parameters\": [\n            \"xyz\",\n            \"number\"\n        ],\n        \"name\": \"Complex rule\",\n        \"parent_id\": null\n    },\n    \"if\": {\n        \"and\": [\n            {\n                \"condition\": {\n                    \"metadata\": {\n                        \"version\": \"0.3.0\",\n                        \"type\": \"Condition\",\n                        \"id\": \"16a74acf-3dfd-4c8f-a280-50dc3970455c\",\n                        \"created\": \"2023-12-15 04:54:00.349063\",\n                        \"required_context_parameters\": [\n                            \"number\"\n                        ]\n                    },\n                    \"variable\": \"number\",\n                    \"operator\": \"in\",\n                    \"value\": {\n                        \"type\": \"list\",\n                        \"value\": [\n                            {\n                                \"type\": \"int\",\n                                \"value\": 1\n                            },\n                            {\n                                \"type\": \"int\",\n                                \"value\": 2\n                            },\n                            {\n                                \"type\": \"int\",\n                                \"value\": 3\n                            }\n                        ]\n                    }\n                }\n            },\n            {\n                \"condition\": {\n                    \"metadata\": {\n                        \"version\": \"0.3.0\",\n                        \"type\": \"Condition\",\n                        \"id\": \"137af61f-16af-44b9-8c49-a1c61912704b\",\n                        \"created\": \"2023-12-15 04:54:00.349134\",\n                        \"required_context_parameters\": [\n                            \"number\"\n                        ]\n                    },\n                    \"variable\": \"number\",\n                    \"operator\": \"=\",\n                    \"value\": {\n                        \"type\": \"int\",\n                        \"value\": 1\n                    }\n                }\n            }\n        ]\n    },\n    \"then\": {\n        \"result\": {\n            \"xyz\": {\n                \"type\": \"str\",\n                \"value\": \"Condition met\"\n            },\n            \"result\": {\n                \"type\": \"variable\",\n                \"value\": \"xyz\"\n            }\n        }\n    },\n    \"else\": {\n        \"metadata\": {\n            \"version\": \"0.3.0\",\n            \"type\": \"Rule\",\n            \"id\": \"41ad9aa7-d072-49d1-9336-4186a3a6b69c\",\n            \"created\": \"2023-12-15 04:54:00.349189\",\n            \"required_context_parameters\": [\n                \"number\"\n            ],\n            \"name\": \"Nested rule\",\n            \"parent_id\": null\n        },\n        \"if\": {\n            \"condition\": {\n                \"metadata\": {\n                    \"version\": \"0.3.0\",\n                    \"type\": \"Condition\",\n                    \"id\": \"16a74acf-3dfd-4c8f-a280-50dc3970455c\",\n                    \"created\": \"2023-12-15 04:54:00.349063\",\n                    \"required_context_parameters\": [\n                        \"number\"\n                    ]\n                },\n                \"variable\": \"number\",\n                \"operator\": \"in\",\n                \"value\": {\n                    \"type\": \"list\",\n                    \"value\": [\n                        {\n                            \"type\": \"int\",\n                            \"value\": 1\n                        },\n                        {\n                            \"type\": \"int\",\n                            \"value\": 2\n                        },\n                        {\n                            \"type\": \"int\",\n                            \"value\": 3\n                        }\n                    ]\n                }\n            }\n        },\n        \"then\": {\n            \"result\": {\n                \"xyz\": {\n                    \"type\": \"str\",\n                    \"value\": \"Condition met\"\n                }\n            }\n        }\n    }\n}\n\n```\n\n\n`rule.yaml`\n\n\n```yaml\n\nmetadata:\n    version: 0.3.0\n    type: Rule\n    id: 8330dd39-a0a4-4f21-aab4-0f8e35924c74\n    created: '2023-12-15 04:54:00.349206'\n    required_context_parameters:\n    - xyz\n    - number\n    name: Complex rule\n    parent_id: null\nif:\n    and:\n    -   condition:\n            metadata:\n                version: 0.3.0\n                type: Condition\n                id: 16a74acf-3dfd-4c8f-a280-50dc3970455c\n                created: '2023-12-15 04:54:00.349063'\n                required_context_parameters:\n                - number\n            variable: number\n            operator: in\n            value:\n                type: list\n                value:\n                -   type: int\n                    value: 1\n                -   type: int\n                    value: 2\n                -   type: int\n                    value: 3\n    -   condition:\n            metadata:\n                version: 0.3.0\n                type: Condition\n                id: 137af61f-16af-44b9-8c49-a1c61912704b\n                created: '2023-12-15 04:54:00.349134'\n                required_context_parameters:\n                - number\n            variable: number\n            operator: '='\n            value:\n                type: int\n                value: 1\nthen:\n    result:\n        xyz:\n            type: str\n            value: Condition met\n        result:\n            type: variable\n            value: xyz\nelse:\n    metadata:\n        version: 0.3.0\n        type: Rule\n        id: 41ad9aa7-d072-49d1-9336-4186a3a6b69c\n        created: '2023-12-15 04:54:00.349189'\n        required_context_parameters:\n        - number\n        name: Nested rule\n        parent_id: null\n    if:\n        condition:\n            metadata:\n                version: 0.3.0\n                type: Condition\n                id: 16a74acf-3dfd-4c8f-a280-50dc3970455c\n                created: '2023-12-15 04:54:00.349063'\n                required_context_parameters:\n                - number\n            variable: number\n            operator: in\n            value:\n                type: list\n                value:\n                -   type: int\n                    value: 1\n                -   type: int\n                    value: 2\n                -   type: int\n                    value: 3\n    then:\n        result:\n            xyz:\n                type: str\n                value: Condition met\n\n\n```\n\n[Go back to top](#table-of-contents)\n\u003cbr\u003e\n\n\u003cspan id=\"tests\"\u003e\u003c/span\u003e\n## Tests\n\nInstall all dev dependencies\n\n```sh\n$ pip install dev-requirements.txt\n```\n\nRun tests -\n\n```sh\npython -m unittest -v\n```\n\n\n\u003cspan id=\"todo\"\u003e\u003c/span\u003e\n## To do\n\n- Pass a global config dictionary from `RuleEngine` to control the following -\n    - Date parsing functions\n    - Rule metadata creation\n\n\n[Go back to top](#table-of-contents)\n\u003cbr\u003e\n\u003chr\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaurabh0719%2Fpy-rules-engine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaurabh0719%2Fpy-rules-engine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaurabh0719%2Fpy-rules-engine/lists"}