We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
no-handler: should not react on when-conditions containing "and" or "or"
<!--- Verify first that your issue is not already reported on GitHub -->
<!--- Also test if the latest release and master branch are affected too -->

##### Summary
Right now the rule `Tasks that run when changed should likely be handlers` (which BTW, i am a big fan of) would produce findings for all of this lines:

`when: mytask.changed`
`when: mytask is changed`
...
`when: mytask is changed and wartherIsNice|bool`

While i totally agree that the first two examples are bad practices and should produce a linter warning, i would not agree, that the last example should.

##### Proposed solution

As mentioned in #419 i could imagine of splitting up E503 into two rules, one of which reacts to single conditions and one for more complex conditions involving `and` or `or` - that way both could be skipped/disabled seperately.

As @ssbarnea pointed out, it might also be a solution to disable the check completeley for complex conditons.

##### Issue Type

- Bug Report


- ansible installation method: OS package
- ansible-lint installation method: pip






--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/ansiblelint/rules/no_handler.py`
Content:
```
1 # Copyright (c) 2016 Will Thames <will@thames.id.au>
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
12 #
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 # THE SOFTWARE.
20 
21 """UseHandlerRatherThanWhenChangedRule used with ansible-lint."""
22 from __future__ import annotations
23 
24 import sys
25 from typing import TYPE_CHECKING
26 
27 from ansiblelint.rules import AnsibleLintRule
28 
29 if TYPE_CHECKING:
30     from ansiblelint.file_utils import Lintable
31     from ansiblelint.utils import Task
32 
33 
34 def _changed_in_when(item: str) -> bool:
35     if not isinstance(item, str):
36         return False
37     item_list = item.split()
38 
39     if {"and", "not"} & set(item_list):
40         return False
41     return any(
42         changed in item
43         for changed in [
44             ".changed",
45             "|changed",
46             '["changed"]',
47             "['changed']",
48             "is changed",
49         ]
50     )
51 
52 
53 class UseHandlerRatherThanWhenChangedRule(AnsibleLintRule):
54     """Tasks that run when changed should likely be handlers."""
55 
56     id = "no-handler"
57     description = (
58         "If a task has a ``when: result.changed`` setting, it is effectively "
59         "acting as a handler. You could use ``notify`` and move that task to "
60         "``handlers``."
61     )
62     link = "https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#handlers"
63     severity = "MEDIUM"
64     tags = ["idiom"]
65     version_added = "historic"
66 
67     def matchtask(
68         self,
69         task: Task,
70         file: Lintable | None = None,
71     ) -> bool | str:
72         if task["__ansible_action_type__"] != "task":
73             return False
74 
75         when = task.get("when")
76 
77         if isinstance(when, list):
78             for item in when:
79                 if _changed_in_when(item):
80                     return True
81         if isinstance(when, str):
82             return _changed_in_when(when)
83         return False
84 
85 
86 if "pytest" in sys.modules:
87     import pytest
88 
89     from ansiblelint.rules import RulesCollection  # pylint: disable=ungrouped-imports
90     from ansiblelint.runner import Runner  # pylint: disable=ungrouped-imports
91 
92     @pytest.mark.parametrize(
93         ("test_file", "failures"),
94         (
95             pytest.param("examples/playbooks/no_handler_fail.yml", 7, id="fail"),
96             pytest.param("examples/playbooks/no_handler_pass.yml", 0, id="pass"),
97         ),
98     )
99     def test_no_handler(
100         default_rules_collection: RulesCollection,
101         test_file: str,
102         failures: int,
103     ) -> None:
104         """Test rule matches."""
105         results = Runner(test_file, rules=default_rules_collection).run()
106         assert len(results) == failures
107         for result in results:
108             assert result.tag == "no-handler"
109
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/ansiblelint/rules/no_handler.py b/src/ansiblelint/rules/no_handler.py
--- a/src/ansiblelint/rules/no_handler.py
+++ b/src/ansiblelint/rules/no_handler.py
@@ -36,7 +36,7 @@
         return False
     item_list = item.split()
 
-    if {"and", "not"} & set(item_list):
+    if {"and", "or", "not"} & set(item_list):
         return False
     return any(
         changed in item
@@ -75,9 +75,9 @@
         when = task.get("when")
 
         if isinstance(when, list):
-            for item in when:
-                if _changed_in_when(item):
-                    return True
+            if len(when) > 1:
+                return False
+            return _changed_in_when(when[0])
         if isinstance(when, str):
             return _changed_in_when(when)
         return False
@@ -92,7 +92,7 @@
     @pytest.mark.parametrize(
         ("test_file", "failures"),
         (
-            pytest.param("examples/playbooks/no_handler_fail.yml", 7, id="fail"),
+            pytest.param("examples/playbooks/no_handler_fail.yml", 5, id="fail"),
             pytest.param("examples/playbooks/no_handler_pass.yml", 0, id="pass"),
         ),
     )

{"golden_diff": "diff --git a/src/ansiblelint/rules/no_handler.py b/src/ansiblelint/rules/no_handler.py\n--- a/src/ansiblelint/rules/no_handler.py\n+++ b/src/ansiblelint/rules/no_handler.py\n@@ -36,7 +36,7 @@\n         return False\n     item_list = item.split()\n \n-    if {\"and\", \"not\"} & set(item_list):\n+    if {\"and\", \"or\", \"not\"} & set(item_list):\n         return False\n     return any(\n         changed in item\n@@ -75,9 +75,9 @@\n         when = task.get(\"when\")\n \n         if isinstance(when, list):\n-            for item in when:\n-                if _changed_in_when(item):\n-                    return True\n+            if len(when) > 1:\n+                return False\n+            return _changed_in_when(when[0])\n         if isinstance(when, str):\n             return _changed_in_when(when)\n         return False\n@@ -92,7 +92,7 @@\n     @pytest.mark.parametrize(\n         (\"test_file\", \"failures\"),\n         (\n-            pytest.param(\"examples/playbooks/no_handler_fail.yml\", 7, id=\"fail\"),\n+            pytest.param(\"examples/playbooks/no_handler_fail.yml\", 5, id=\"fail\"),\n             pytest.param(\"examples/playbooks/no_handler_pass.yml\", 0, id=\"pass\"),\n         ),\n     )\n", "issue": "no-handler: should not react on when-conditions containing \"and\" or \"or\"\n<!--- Verify first that your issue is not already reported on GitHub -->\r\n<!--- Also test if the latest release and master branch are affected too -->\r\n\r\n##### Summary\r\nRight now the rule `Tasks that run when changed should likely be handlers` (which BTW, i am a big fan of) would produce findings for all of this lines:\r\n\r\n`when: mytask.changed`\r\n`when: mytask is changed`\r\n...\r\n`when: mytask is changed and wartherIsNice|bool`\r\n\r\nWhile i totally agree that the first two examples are bad practices and should produce a linter warning, i would not agree, that the last example should.\r\n\r\n##### Proposed solution\r\n\r\nAs mentioned in #419 i could imagine of splitting up E503 into two rules, one of which reacts to single conditions and one for more complex conditions involving `and` or `or` - that way both could be skipped/disabled seperately.\r\n\r\nAs @ssbarnea pointed out, it might also be a solution to disable the check completeley for complex conditons.\r\n\r\n##### Issue Type\r\n\r\n- Bug Report\r\n\r\n\r\n- ansible installation method: OS package\r\n- ansible-lint installation method: pip\r\n\r\n\r\n\r\n\r\n\n", "before_files": [{"content": "# Copyright (c) 2016 Will Thames <will@thames.id.au>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n\"\"\"UseHandlerRatherThanWhenChangedRule used with ansible-lint.\"\"\"\nfrom __future__ import annotations\n\nimport sys\nfrom typing import TYPE_CHECKING\n\nfrom ansiblelint.rules import AnsibleLintRule\n\nif TYPE_CHECKING:\n    from ansiblelint.file_utils import Lintable\n    from ansiblelint.utils import Task\n\n\ndef _changed_in_when(item: str) -> bool:\n    if not isinstance(item, str):\n        return False\n    item_list = item.split()\n\n    if {\"and\", \"not\"} & set(item_list):\n        return False\n    return any(\n        changed in item\n        for changed in [\n            \".changed\",\n            \"|changed\",\n            '[\"changed\"]',\n            \"['changed']\",\n            \"is changed\",\n        ]\n    )\n\n\nclass UseHandlerRatherThanWhenChangedRule(AnsibleLintRule):\n    \"\"\"Tasks that run when changed should likely be handlers.\"\"\"\n\n    id = \"no-handler\"\n    description = (\n        \"If a task has a ``when: result.changed`` setting, it is effectively \"\n        \"acting as a handler. You could use ``notify`` and move that task to \"\n        \"``handlers``.\"\n    )\n    link = \"https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#handlers\"\n    severity = \"MEDIUM\"\n    tags = [\"idiom\"]\n    version_added = \"historic\"\n\n    def matchtask(\n        self,\n        task: Task,\n        file: Lintable | None = None,\n    ) -> bool | str:\n        if task[\"__ansible_action_type__\"] != \"task\":\n            return False\n\n        when = task.get(\"when\")\n\n        if isinstance(when, list):\n            for item in when:\n                if _changed_in_when(item):\n                    return True\n        if isinstance(when, str):\n            return _changed_in_when(when)\n        return False\n\n\nif \"pytest\" in sys.modules:\n    import pytest\n\n    from ansiblelint.rules import RulesCollection  # pylint: disable=ungrouped-imports\n    from ansiblelint.runner import Runner  # pylint: disable=ungrouped-imports\n\n    @pytest.mark.parametrize(\n        (\"test_file\", \"failures\"),\n        (\n            pytest.param(\"examples/playbooks/no_handler_fail.yml\", 7, id=\"fail\"),\n            pytest.param(\"examples/playbooks/no_handler_pass.yml\", 0, id=\"pass\"),\n        ),\n    )\n    def test_no_handler(\n        default_rules_collection: RulesCollection,\n        test_file: str,\n        failures: int,\n    ) -> None:\n        \"\"\"Test rule matches.\"\"\"\n        results = Runner(test_file, rules=default_rules_collection).run()\n        assert len(results) == failures\n        for result in results:\n            assert result.tag == \"no-handler\"\n", "path": "src/ansiblelint/rules/no_handler.py"}], "after_files": [{"content": "# Copyright (c) 2016 Will Thames <will@thames.id.au>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n\"\"\"UseHandlerRatherThanWhenChangedRule used with ansible-lint.\"\"\"\nfrom __future__ import annotations\n\nimport sys\nfrom typing import TYPE_CHECKING\n\nfrom ansiblelint.rules import AnsibleLintRule\n\nif TYPE_CHECKING:\n    from ansiblelint.file_utils import Lintable\n    from ansiblelint.utils import Task\n\n\ndef _changed_in_when(item: str) -> bool:\n    if not isinstance(item, str):\n        return False\n    item_list = item.split()\n\n    if {\"and\", \"or\", \"not\"} & set(item_list):\n        return False\n    return any(\n        changed in item\n        for changed in [\n            \".changed\",\n            \"|changed\",\n            '[\"changed\"]',\n            \"['changed']\",\n            \"is changed\",\n        ]\n    )\n\n\nclass UseHandlerRatherThanWhenChangedRule(AnsibleLintRule):\n    \"\"\"Tasks that run when changed should likely be handlers.\"\"\"\n\n    id = \"no-handler\"\n    description = (\n        \"If a task has a ``when: result.changed`` setting, it is effectively \"\n        \"acting as a handler. You could use ``notify`` and move that task to \"\n        \"``handlers``.\"\n    )\n    link = \"https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#handlers\"\n    severity = \"MEDIUM\"\n    tags = [\"idiom\"]\n    version_added = \"historic\"\n\n    def matchtask(\n        self,\n        task: Task,\n        file: Lintable | None = None,\n    ) -> bool | str:\n        if task[\"__ansible_action_type__\"] != \"task\":\n            return False\n\n        when = task.get(\"when\")\n\n        if isinstance(when, list):\n            if len(when) > 1:\n                return False\n            return _changed_in_when(when[0])\n        if isinstance(when, str):\n            return _changed_in_when(when)\n        return False\n\n\nif \"pytest\" in sys.modules:\n    import pytest\n\n    from ansiblelint.rules import RulesCollection  # pylint: disable=ungrouped-imports\n    from ansiblelint.runner import Runner  # pylint: disable=ungrouped-imports\n\n    @pytest.mark.parametrize(\n        (\"test_file\", \"failures\"),\n        (\n            pytest.param(\"examples/playbooks/no_handler_fail.yml\", 5, id=\"fail\"),\n            pytest.param(\"examples/playbooks/no_handler_pass.yml\", 0, id=\"pass\"),\n        ),\n    )\n    def test_no_handler(\n        default_rules_collection: RulesCollection,\n        test_file: str,\n        failures: int,\n    ) -> None:\n        \"\"\"Test rule matches.\"\"\"\n        results = Runner(test_file, rules=default_rules_collection).run()\n        assert len(results) == failures\n        for result in results:\n            assert result.tag == \"no-handler\"\n", "path": "src/ansiblelint/rules/no_handler.py"}]}