prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  tools.environment_append raises if tries to unset variable which was never set
  after #4224, I may use the following code, for instance, to ensure variable is not set:
  ```
  with environment_append({'CONAN_BASH_PATH': None}):
      pass
  ```
  however, it raises if `CONAN_BASH_PATH` is not set (prior to the environment_append invocation):
  ```
  Traceback (most recent call last):
    File "C:\bincrafters\conan\conans\test\unittests\client\tools\os_info\osinfo_test.py", line 39, in test_windows
      with environment_append(new_env):
    File "c:\users\sse4\appdata\local\programs\python\python36\lib\contextlib.py", line 81, in __enter__
      return next(self.gen)
    File "C:\bincrafters\conan\conans\client\tools\env.py", line 57, in environment_append
      os.environ.pop(var)
    File "c:\users\sse4\appdata\local\programs\python\python36\lib\_collections_abc.py", line 795, in pop
      value = self[key]
    File "c:\users\sse4\appdata\local\programs\python\python36\lib\os.py", line 669, in __getitem__
      raise KeyError(key) from None
  KeyError: 'CONAN_BASH_PATH'
  ```
  I would expect `tools.environment_append` to be no op in such case, otherwise, it requires additional logic to workaround this behavior.
  
  To help us debug your issue please explain:
  
  - [ ] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
  - [ ] I've specified the Conan version, operating system version and any tool that can be relevant.
  - [ ] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.
  
  
  
  </issue>
  <code>
  [start of conans/client/tools/env.py]
  1 import os
  2 import sys
  3 from contextlib import contextmanager
  4 
  5 from conans.client.run_environment import RunEnvironment
  6 from conans.client.tools.files import _path_equals, which
  7 from conans.errors import ConanException
  8 
  9 
  10 @contextmanager
  11 def pythonpath(conanfile):
  12     python_path = conanfile.env.get("PYTHONPATH", None)
  13     if python_path:
  14         old_path = sys.path[:]
  15         if isinstance(python_path, list):
  16             sys.path.extend(python_path)
  17         else:
  18             sys.path.append(python_path)
  19 
  20         yield
  21         sys.path = old_path
  22     else:
  23         yield
  24 
  25 
  26 @contextmanager
  27 def run_environment(conanfile):
  28     with environment_append(RunEnvironment(conanfile).vars):
  29         yield
  30 
  31 
  32 @contextmanager
  33 def environment_append(env_vars):
  34     """
  35     :param env_vars: List (dict) of simple environment vars. {name: value, name2: value2} => e.g.: MYVAR=1
  36                      The values can also be lists of appendable environment vars. {name: [value, value2]}
  37                       => e.g. PATH=/path/1:/path/2
  38                      If the value is set to None, then that environment variable is unset.
  39     :return: None
  40     """
  41     unset_vars = []
  42     for key in env_vars.keys():
  43         if env_vars[key] is None:
  44             unset_vars.append(key)
  45     for var in unset_vars:
  46         env_vars.pop(var, None)
  47     for name, value in env_vars.items():
  48         if isinstance(value, list):
  49             env_vars[name] = os.pathsep.join(value)
  50             old = os.environ.get(name)
  51             if old:
  52                 env_vars[name] += os.pathsep + old
  53     if env_vars or unset_vars:
  54         old_env = dict(os.environ)
  55         os.environ.update(env_vars)
  56         for var in unset_vars:
  57             os.environ.pop(var)
  58         try:
  59             yield
  60         finally:
  61             os.environ.clear()
  62             os.environ.update(old_env)
  63     else:
  64         yield
  65 
  66 
  67 @contextmanager
  68 def no_op():
  69     yield
  70 
  71 
  72 @contextmanager
  73 def remove_from_path(command):
  74     curpath = os.getenv("PATH")
  75     first_it = True
  76     for _ in range(30):
  77         if not first_it:
  78             with environment_append({"PATH": curpath}):
  79                 the_command = which(command)
  80         else:
  81             the_command = which(command)
  82             first_it = False
  83 
  84         if not the_command:
  85             break
  86         new_path = []
  87         for entry in curpath.split(os.pathsep):
  88             if not _path_equals(entry, os.path.dirname(the_command)):
  89                 new_path.append(entry)
  90 
  91         curpath = os.pathsep.join(new_path)
  92     else:
  93         raise ConanException("Error in tools.remove_from_path!! couldn't remove the tool '%s' "
  94                              "from the path after 30 attempts, still found in '%s' this is a "
  95                              "Conan client bug, please open an issue at: "
  96                              "https://github.com/conan-io/conan\n\nPATH=%s"
  97                              % (command, the_command, os.getenv("PATH")))
  98 
  99     with environment_append({"PATH": curpath}):
  100         yield
  101
  [end of conans/client/tools/env.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/conans/client/tools/env.py b/conans/client/tools/env.py
  --- a/conans/client/tools/env.py
  +++ b/conans/client/tools/env.py
  @@ -54,7 +54,7 @@
           old_env = dict(os.environ)
           os.environ.update(env_vars)
           for var in unset_vars:
  -            os.environ.pop(var)
  +            os.environ.pop(var, None)
           try:
               yield
           finally:
  
verification_info: {"golden_diff": "diff --git a/conans/client/tools/env.py b/conans/client/tools/env.py\n--- a/conans/client/tools/env.py\n+++ b/conans/client/tools/env.py\n@@ -54,7 +54,7 @@\n         old_env = dict(os.environ)\n         os.environ.update(env_vars)\n         for var in unset_vars:\n-            os.environ.pop(var)\n+            os.environ.pop(var, None)\n         try:\n             yield\n         finally:\n", "issue": "tools.environment_append raises if tries to unset variable which was never set\nafter #4224, I may use the following code, for instance, to ensure variable is not set:\r\n```\r\nwith environment_append({'CONAN_BASH_PATH': None}):\r\n    pass\r\n```\r\nhowever, it raises if `CONAN_BASH_PATH` is not set (prior to the environment_append invocation):\r\n```\r\nTraceback (most recent call last):\r\n  File \"C:\\bincrafters\\conan\\conans\\test\\unittests\\client\\tools\\os_info\\osinfo_test.py\", line 39, in test_windows\r\n    with environment_append(new_env):\r\n  File \"c:\\users\\sse4\\appdata\\local\\programs\\python\\python36\\lib\\contextlib.py\", line 81, in __enter__\r\n    return next(self.gen)\r\n  File \"C:\\bincrafters\\conan\\conans\\client\\tools\\env.py\", line 57, in environment_append\r\n    os.environ.pop(var)\r\n  File \"c:\\users\\sse4\\appdata\\local\\programs\\python\\python36\\lib\\_collections_abc.py\", line 795, in pop\r\n    value = self[key]\r\n  File \"c:\\users\\sse4\\appdata\\local\\programs\\python\\python36\\lib\\os.py\", line 669, in __getitem__\r\n    raise KeyError(key) from None\r\nKeyError: 'CONAN_BASH_PATH'\r\n```\r\nI would expect `tools.environment_append` to be no op in such case, otherwise, it requires additional logic to workaround this behavior.\r\n\r\nTo help us debug your issue please explain:\r\n\r\n- [ ] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).\r\n- [ ] I've specified the Conan version, operating system version and any tool that can be relevant.\r\n- [ ] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.\r\n\r\n\n", "before_files": [{"content": "import os\nimport sys\nfrom contextlib import contextmanager\n\nfrom conans.client.run_environment import RunEnvironment\nfrom conans.client.tools.files import _path_equals, which\nfrom conans.errors import ConanException\n\n\n@contextmanager\ndef pythonpath(conanfile):\n    python_path = conanfile.env.get(\"PYTHONPATH\", None)\n    if python_path:\n        old_path = sys.path[:]\n        if isinstance(python_path, list):\n            sys.path.extend(python_path)\n        else:\n            sys.path.append(python_path)\n\n        yield\n        sys.path = old_path\n    else:\n        yield\n\n\n@contextmanager\ndef run_environment(conanfile):\n    with environment_append(RunEnvironment(conanfile).vars):\n        yield\n\n\n@contextmanager\ndef environment_append(env_vars):\n    \"\"\"\n    :param env_vars: List (dict) of simple environment vars. {name: value, name2: value2} => e.g.: MYVAR=1\n                     The values can also be lists of appendable environment vars. {name: [value, value2]}\n                      => e.g. PATH=/path/1:/path/2\n                     If the value is set to None, then that environment variable is unset.\n    :return: None\n    \"\"\"\n    unset_vars = []\n    for key in env_vars.keys():\n        if env_vars[key] is None:\n            unset_vars.append(key)\n    for var in unset_vars:\n        env_vars.pop(var, None)\n    for name, value in env_vars.items():\n        if isinstance(value, list):\n            env_vars[name] = os.pathsep.join(value)\n            old = os.environ.get(name)\n            if old:\n                env_vars[name] += os.pathsep + old\n    if env_vars or unset_vars:\n        old_env = dict(os.environ)\n        os.environ.update(env_vars)\n        for var in unset_vars:\n            os.environ.pop(var)\n        try:\n            yield\n        finally:\n            os.environ.clear()\n            os.environ.update(old_env)\n    else:\n        yield\n\n\n@contextmanager\ndef no_op():\n    yield\n\n\n@contextmanager\ndef remove_from_path(command):\n    curpath = os.getenv(\"PATH\")\n    first_it = True\n    for _ in range(30):\n        if not first_it:\n            with environment_append({\"PATH\": curpath}):\n                the_command = which(command)\n        else:\n            the_command = which(command)\n            first_it = False\n\n        if not the_command:\n            break\n        new_path = []\n        for entry in curpath.split(os.pathsep):\n            if not _path_equals(entry, os.path.dirname(the_command)):\n                new_path.append(entry)\n\n        curpath = os.pathsep.join(new_path)\n    else:\n        raise ConanException(\"Error in tools.remove_from_path!! couldn't remove the tool '%s' \"\n                             \"from the path after 30 attempts, still found in '%s' this is a \"\n                             \"Conan client bug, please open an issue at: \"\n                             \"https://github.com/conan-io/conan\\n\\nPATH=%s\"\n                             % (command, the_command, os.getenv(\"PATH\")))\n\n    with environment_append({\"PATH\": curpath}):\n        yield\n", "path": "conans/client/tools/env.py"}]}