prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <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
  
  
  
  
  
  
  </issue>
  <code>
  [start of src/ansiblelint/rules/no_handler.py]
  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 of src/ansiblelint/rules/no_handler.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: 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"),
           ),
       )
  
verification_info: {"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"}]}