prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Don't expose all params as shell environment variables by default
  _Originally posted by @bpkroth in https://github.com/microsoft/MLOS/pull/557#discussion_r1374921396_
              
  
  </issue>
  <code>
  [start of mlos_bench/mlos_bench/environments/script_env.py]
  1 #
  2 # Copyright (c) Microsoft Corporation.
  3 # Licensed under the MIT License.
  4 #
  5 """
  6 Base scriptable benchmark environment.
  7 """
  8 
  9 import abc
  10 import logging
  11 import re
  12 from typing import Dict, Iterable, Optional
  13 
  14 from mlos_bench.environments.base_environment import Environment
  15 from mlos_bench.services.base_service import Service
  16 from mlos_bench.tunables.tunable import TunableValue
  17 from mlos_bench.tunables.tunable_groups import TunableGroups
  18 
  19 from mlos_bench.util import try_parse_val
  20 
  21 _LOG = logging.getLogger(__name__)
  22 
  23 
  24 class ScriptEnv(Environment, metaclass=abc.ABCMeta):
  25     """
  26     Base Environment that runs scripts for setup/run/teardown.
  27     """
  28 
  29     _RE_INVALID = re.compile(r"[^a-zA-Z0-9_]")
  30 
  31     def __init__(self,
  32                  *,
  33                  name: str,
  34                  config: dict,
  35                  global_config: Optional[dict] = None,
  36                  tunables: Optional[TunableGroups] = None,
  37                  service: Optional[Service] = None):
  38         """
  39         Create a new environment for script execution.
  40 
  41         Parameters
  42         ----------
  43         name: str
  44             Human-readable name of the environment.
  45         config : dict
  46             Free-format dictionary that contains the benchmark environment
  47             configuration. Each config must have at least the `tunable_params`
  48             and the `const_args` sections. It must also have at least one of
  49             the following parameters: {`setup`, `run`, `teardown`}.
  50             Additional parameters:
  51                 * `shell_env_params` - an array of parameters to pass to the script
  52                   as shell environment variables, and
  53                 * `shell_env_params_rename` - a dictionary of {to: from} mappings
  54                   of the script parameters. If not specified, replace all
  55                   non-alphanumeric characters with underscores.
  56             If neither `shell_env_params` nor `shell_env_params_rename` are specified,
  57             pass *all* parameters to the script.
  58         global_config : dict
  59             Free-format dictionary of global parameters (e.g., security credentials)
  60             to be mixed in into the "const_args" section of the local config.
  61         tunables : TunableGroups
  62             A collection of tunable parameters for *all* environments.
  63         service: Service
  64             An optional service object (e.g., providing methods to
  65             deploy or reboot a VM, etc.).
  66         """
  67         super().__init__(name=name, config=config, global_config=global_config,
  68                          tunables=tunables, service=service)
  69 
  70         self._script_setup = self.config.get("setup")
  71         self._script_run = self.config.get("run")
  72         self._script_teardown = self.config.get("teardown")
  73 
  74         self._shell_env_params: Optional[Iterable[str]] = self.config.get("shell_env_params")
  75         self._shell_env_params_rename: Dict[str, str] = self.config.get("shell_env_params_rename", {})
  76 
  77         results_stdout_pattern = self.config.get("results_stdout_pattern")
  78         self._results_stdout_pattern: Optional[re.Pattern[str]] = \
  79             re.compile(results_stdout_pattern) if results_stdout_pattern else None
  80 
  81     def _get_env_params(self) -> Dict[str, str]:
  82         """
  83         Get the *shell* environment parameters to be passed to the script.
  84 
  85         Returns
  86         -------
  87         env_params : Dict[str, str]
  88             Parameters to pass as *shell* environment variables into the script.
  89             This is usually a subset of `_params` with some possible conversions.
  90         """
  91         rename: Dict[str, str]  # {to: from} mapping of the script parameters.
  92         if self._shell_env_params is None:
  93             if self._shell_env_params_rename:
  94                 # Only rename specified - use it.
  95                 rename = self._shell_env_params_rename.copy()
  96             else:
  97                 # FIXME: We should not be exposing all params by default.
  98                 # Neither `shell_env_params` nor rename are specified - use all params.
  99                 rename = {self._RE_INVALID.sub("_", key): key for key in self._params}
  100         else:
  101             # Use `shell_env_params` and rename if specified.
  102             rename = {self._RE_INVALID.sub("_", key): key for key in self._shell_env_params}
  103             rename.update(self._shell_env_params_rename)
  104 
  105         return {key_sub: str(self._params[key]) for (key_sub, key) in rename.items()}
  106 
  107     def _extract_stdout_results(self, stdout: str) -> Dict[str, TunableValue]:
  108         """
  109         Extract the results from the stdout of the script.
  110 
  111         Parameters
  112         ----------
  113         stdout : str
  114             The stdout of the script.
  115 
  116         Returns
  117         -------
  118         results : Dict[str, TunableValue]
  119             A dictionary of results extracted from the stdout.
  120         """
  121         if not self._results_stdout_pattern:
  122             return {}
  123         _LOG.debug("Extract regex: '%s' from: '%s'", self._results_stdout_pattern, stdout)
  124         return {key: try_parse_val(val) for (key, val) in self._results_stdout_pattern.findall(stdout)}
  125
  [end of mlos_bench/mlos_bench/environments/script_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/mlos_bench/mlos_bench/environments/script_env.py b/mlos_bench/mlos_bench/environments/script_env.py
  --- a/mlos_bench/mlos_bench/environments/script_env.py
  +++ b/mlos_bench/mlos_bench/environments/script_env.py
  @@ -54,7 +54,7 @@
                     of the script parameters. If not specified, replace all
                     non-alphanumeric characters with underscores.
               If neither `shell_env_params` nor `shell_env_params_rename` are specified,
  -            pass *all* parameters to the script.
  +            *no* additional shell parameters will be passed to the script.
           global_config : dict
               Free-format dictionary of global parameters (e.g., security credentials)
               to be mixed in into the "const_args" section of the local config.
  @@ -71,7 +71,7 @@
           self._script_run = self.config.get("run")
           self._script_teardown = self.config.get("teardown")
   
  -        self._shell_env_params: Optional[Iterable[str]] = self.config.get("shell_env_params")
  +        self._shell_env_params: Iterable[str] = self.config.get("shell_env_params", [])
           self._shell_env_params_rename: Dict[str, str] = self.config.get("shell_env_params_rename", {})
   
           results_stdout_pattern = self.config.get("results_stdout_pattern")
  @@ -88,20 +88,8 @@
               Parameters to pass as *shell* environment variables into the script.
               This is usually a subset of `_params` with some possible conversions.
           """
  -        rename: Dict[str, str]  # {to: from} mapping of the script parameters.
  -        if self._shell_env_params is None:
  -            if self._shell_env_params_rename:
  -                # Only rename specified - use it.
  -                rename = self._shell_env_params_rename.copy()
  -            else:
  -                # FIXME: We should not be exposing all params by default.
  -                # Neither `shell_env_params` nor rename are specified - use all params.
  -                rename = {self._RE_INVALID.sub("_", key): key for key in self._params}
  -        else:
  -            # Use `shell_env_params` and rename if specified.
  -            rename = {self._RE_INVALID.sub("_", key): key for key in self._shell_env_params}
  -            rename.update(self._shell_env_params_rename)
  -
  +        rename = {self._RE_INVALID.sub("_", key): key for key in self._shell_env_params}
  +        rename.update(self._shell_env_params_rename)
           return {key_sub: str(self._params[key]) for (key_sub, key) in rename.items()}
   
       def _extract_stdout_results(self, stdout: str) -> Dict[str, TunableValue]:
  
verification_info: {"golden_diff": "diff --git a/mlos_bench/mlos_bench/environments/script_env.py b/mlos_bench/mlos_bench/environments/script_env.py\n--- a/mlos_bench/mlos_bench/environments/script_env.py\n+++ b/mlos_bench/mlos_bench/environments/script_env.py\n@@ -54,7 +54,7 @@\n                   of the script parameters. If not specified, replace all\n                   non-alphanumeric characters with underscores.\n             If neither `shell_env_params` nor `shell_env_params_rename` are specified,\n-            pass *all* parameters to the script.\n+            *no* additional shell parameters will be passed to the script.\n         global_config : dict\n             Free-format dictionary of global parameters (e.g., security credentials)\n             to be mixed in into the \"const_args\" section of the local config.\n@@ -71,7 +71,7 @@\n         self._script_run = self.config.get(\"run\")\n         self._script_teardown = self.config.get(\"teardown\")\n \n-        self._shell_env_params: Optional[Iterable[str]] = self.config.get(\"shell_env_params\")\n+        self._shell_env_params: Iterable[str] = self.config.get(\"shell_env_params\", [])\n         self._shell_env_params_rename: Dict[str, str] = self.config.get(\"shell_env_params_rename\", {})\n \n         results_stdout_pattern = self.config.get(\"results_stdout_pattern\")\n@@ -88,20 +88,8 @@\n             Parameters to pass as *shell* environment variables into the script.\n             This is usually a subset of `_params` with some possible conversions.\n         \"\"\"\n-        rename: Dict[str, str]  # {to: from} mapping of the script parameters.\n-        if self._shell_env_params is None:\n-            if self._shell_env_params_rename:\n-                # Only rename specified - use it.\n-                rename = self._shell_env_params_rename.copy()\n-            else:\n-                # FIXME: We should not be exposing all params by default.\n-                # Neither `shell_env_params` nor rename are specified - use all params.\n-                rename = {self._RE_INVALID.sub(\"_\", key): key for key in self._params}\n-        else:\n-            # Use `shell_env_params` and rename if specified.\n-            rename = {self._RE_INVALID.sub(\"_\", key): key for key in self._shell_env_params}\n-            rename.update(self._shell_env_params_rename)\n-\n+        rename = {self._RE_INVALID.sub(\"_\", key): key for key in self._shell_env_params}\n+        rename.update(self._shell_env_params_rename)\n         return {key_sub: str(self._params[key]) for (key_sub, key) in rename.items()}\n \n     def _extract_stdout_results(self, stdout: str) -> Dict[str, TunableValue]:\n", "issue": "Don't expose all params as shell environment variables by default\n_Originally posted by @bpkroth in https://github.com/microsoft/MLOS/pull/557#discussion_r1374921396_\r\n            \n", "before_files": [{"content": "#\n# Copyright (c) Microsoft Corporation.\n# Licensed under the MIT License.\n#\n\"\"\"\nBase scriptable benchmark environment.\n\"\"\"\n\nimport abc\nimport logging\nimport re\nfrom typing import Dict, Iterable, Optional\n\nfrom mlos_bench.environments.base_environment import Environment\nfrom mlos_bench.services.base_service import Service\nfrom mlos_bench.tunables.tunable import TunableValue\nfrom mlos_bench.tunables.tunable_groups import TunableGroups\n\nfrom mlos_bench.util import try_parse_val\n\n_LOG = logging.getLogger(__name__)\n\n\nclass ScriptEnv(Environment, metaclass=abc.ABCMeta):\n    \"\"\"\n    Base Environment that runs scripts for setup/run/teardown.\n    \"\"\"\n\n    _RE_INVALID = re.compile(r\"[^a-zA-Z0-9_]\")\n\n    def __init__(self,\n                 *,\n                 name: str,\n                 config: dict,\n                 global_config: Optional[dict] = None,\n                 tunables: Optional[TunableGroups] = None,\n                 service: Optional[Service] = None):\n        \"\"\"\n        Create a new environment for script execution.\n\n        Parameters\n        ----------\n        name: str\n            Human-readable name of the environment.\n        config : dict\n            Free-format dictionary that contains the benchmark environment\n            configuration. Each config must have at least the `tunable_params`\n            and the `const_args` sections. It must also have at least one of\n            the following parameters: {`setup`, `run`, `teardown`}.\n            Additional parameters:\n                * `shell_env_params` - an array of parameters to pass to the script\n                  as shell environment variables, and\n                * `shell_env_params_rename` - a dictionary of {to: from} mappings\n                  of the script parameters. If not specified, replace all\n                  non-alphanumeric characters with underscores.\n            If neither `shell_env_params` nor `shell_env_params_rename` are specified,\n            pass *all* parameters to the script.\n        global_config : dict\n            Free-format dictionary of global parameters (e.g., security credentials)\n            to be mixed in into the \"const_args\" section of the local config.\n        tunables : TunableGroups\n            A collection of tunable parameters for *all* environments.\n        service: Service\n            An optional service object (e.g., providing methods to\n            deploy or reboot a VM, etc.).\n        \"\"\"\n        super().__init__(name=name, config=config, global_config=global_config,\n                         tunables=tunables, service=service)\n\n        self._script_setup = self.config.get(\"setup\")\n        self._script_run = self.config.get(\"run\")\n        self._script_teardown = self.config.get(\"teardown\")\n\n        self._shell_env_params: Optional[Iterable[str]] = self.config.get(\"shell_env_params\")\n        self._shell_env_params_rename: Dict[str, str] = self.config.get(\"shell_env_params_rename\", {})\n\n        results_stdout_pattern = self.config.get(\"results_stdout_pattern\")\n        self._results_stdout_pattern: Optional[re.Pattern[str]] = \\\n            re.compile(results_stdout_pattern) if results_stdout_pattern else None\n\n    def _get_env_params(self) -> Dict[str, str]:\n        \"\"\"\n        Get the *shell* environment parameters to be passed to the script.\n\n        Returns\n        -------\n        env_params : Dict[str, str]\n            Parameters to pass as *shell* environment variables into the script.\n            This is usually a subset of `_params` with some possible conversions.\n        \"\"\"\n        rename: Dict[str, str]  # {to: from} mapping of the script parameters.\n        if self._shell_env_params is None:\n            if self._shell_env_params_rename:\n                # Only rename specified - use it.\n                rename = self._shell_env_params_rename.copy()\n            else:\n                # FIXME: We should not be exposing all params by default.\n                # Neither `shell_env_params` nor rename are specified - use all params.\n                rename = {self._RE_INVALID.sub(\"_\", key): key for key in self._params}\n        else:\n            # Use `shell_env_params` and rename if specified.\n            rename = {self._RE_INVALID.sub(\"_\", key): key for key in self._shell_env_params}\n            rename.update(self._shell_env_params_rename)\n\n        return {key_sub: str(self._params[key]) for (key_sub, key) in rename.items()}\n\n    def _extract_stdout_results(self, stdout: str) -> Dict[str, TunableValue]:\n        \"\"\"\n        Extract the results from the stdout of the script.\n\n        Parameters\n        ----------\n        stdout : str\n            The stdout of the script.\n\n        Returns\n        -------\n        results : Dict[str, TunableValue]\n            A dictionary of results extracted from the stdout.\n        \"\"\"\n        if not self._results_stdout_pattern:\n            return {}\n        _LOG.debug(\"Extract regex: '%s' from: '%s'\", self._results_stdout_pattern, stdout)\n        return {key: try_parse_val(val) for (key, val) in self._results_stdout_pattern.findall(stdout)}\n", "path": "mlos_bench/mlos_bench/environments/script_env.py"}]}