We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Save .hydra/*.yaml before task execution
# 🐛 Bug

Saving the configurations is a really cool idea that helps me check what I actually did. I noticed the save timing is delayed after task execution in the `1.0.0rc1`. I have encountered some scenarios that I think it would be better if the configs are saved earlier.

For example,

1. Tasks may exit accidentally due to bugs. Knowing detailed configurations would be helpful.
2. For time-consuming tasks like ML training which may last for several days, it would be helpful to be able to check the config.yaml. This helps me a lot when I have multiple tasks running but I can't remember the real difference. I do `diff config.yaml`.
3. Some tasks don't need to be finished. The full training may be designed to run 100 epochs but it also happens it's aborted/killed in the middle.

## To reproduce

Default behavior in `1.0.0rc1`.

** Minimal Code/Config snippet to reproduce **
NA

** Stack trace/error message **
NA

## Expected Behavior
NA

## System information
- **Hydra Version** :  1.0.0rc1
- **Python version** : NA
- **Virtual environment type and version** : NA
- **Operating system** : NA



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `hydra/core/utils.py`
Content:
```
1 # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
2 import copy
3 import logging
4 import os
5 import re
6 import sys
7 import warnings
8 from contextlib import contextmanager
9 from dataclasses import dataclass
10 from os.path import basename, dirname, splitext
11 from pathlib import Path
12 from time import localtime, strftime
13 from typing import Any, Dict, Optional, Sequence, Tuple, Union, cast
14 
15 from omegaconf import DictConfig, OmegaConf, open_dict
16 
17 from hydra.core.hydra_config import HydraConfig
18 from hydra.core.singleton import Singleton
19 from hydra.types import TaskFunction
20 
21 log = logging.getLogger(__name__)
22 
23 
24 def simple_stdout_log_config(level: int = logging.INFO) -> None:
25     root = logging.getLogger()
26     root.setLevel(level)
27     handler = logging.StreamHandler(sys.stdout)
28     formatter = logging.Formatter("%(message)s")
29     handler.setFormatter(formatter)
30     root.addHandler(handler)
31 
32 
33 def configure_log(
34     log_config: DictConfig, verbose_config: Union[bool, str, Sequence[str]]
35 ) -> None:
36     assert isinstance(verbose_config, (bool, str)) or OmegaConf.is_list(verbose_config)
37     if log_config is not None:
38         conf: Dict[str, Any] = OmegaConf.to_container(  # type: ignore
39             log_config, resolve=True
40         )
41         logging.config.dictConfig(conf)
42     else:
43         # default logging to stdout
44         root = logging.getLogger()
45         root.setLevel(logging.INFO)
46         handler = logging.StreamHandler(sys.stdout)
47         formatter = logging.Formatter(
48             "[%(asctime)s][%(name)s][%(levelname)s] - %(message)s"
49         )
50         handler.setFormatter(formatter)
51         root.addHandler(handler)
52     if isinstance(verbose_config, bool):
53         if verbose_config:
54             logging.getLogger().setLevel(logging.DEBUG)
55     else:
56         if isinstance(verbose_config, str):
57             verbose_list = OmegaConf.create([verbose_config])
58         elif OmegaConf.is_list(verbose_config):
59             verbose_list = verbose_config  # type: ignore
60         else:
61             assert False
62 
63         for logger in verbose_list:
64             logging.getLogger(logger).setLevel(logging.DEBUG)
65 
66 
67 def _save_config(cfg: DictConfig, filename: str, output_dir: Path) -> None:
68     output_dir.mkdir(parents=True, exist_ok=True)
69     with open(str(output_dir / filename), "w") as file:
70         file.write(cfg.pretty())
71 
72 
73 def filter_overrides(overrides: Sequence[str]) -> Sequence[str]:
74     """
75     :param overrides: overrides list
76     :return: returning a new overrides list with all the keys starting with hydra. filtered.
77     """
78     return [x for x in overrides if not x.startswith("hydra.")]
79 
80 
81 def run_job(
82     config: DictConfig,
83     task_function: TaskFunction,
84     job_dir_key: str,
85     job_subdir_key: Optional[str],
86 ) -> "JobReturn":
87     old_cwd = os.getcwd()
88     working_dir = str(OmegaConf.select(config, job_dir_key))
89     if job_subdir_key is not None:
90         # evaluate job_subdir_key lazily.
91         # this is running on the client side in sweep and contains things such as job:id which
92         # are only available there.
93         subdir = str(OmegaConf.select(config, job_subdir_key))
94         working_dir = os.path.join(working_dir, subdir)
95     try:
96         ret = JobReturn()
97         ret.working_dir = working_dir
98         task_cfg = copy.deepcopy(config)
99         with open_dict(task_cfg):
100             del task_cfg["hydra"]
101         ret.cfg = task_cfg
102         ret.hydra_cfg = OmegaConf.create({"hydra": HydraConfig.get()})
103         overrides = OmegaConf.to_container(config.hydra.overrides.task)
104         assert isinstance(overrides, list)
105         ret.overrides = overrides
106         # handle output directories here
107         Path(str(working_dir)).mkdir(parents=True, exist_ok=True)
108         os.chdir(working_dir)
109 
110         configure_log(config.hydra.job_logging, config.hydra.verbose)
111 
112         hydra_cfg = OmegaConf.masked_copy(config, "hydra")
113         assert isinstance(hydra_cfg, DictConfig)
114 
115         with env_override(hydra_cfg.hydra.job.env_set):
116             ret.return_value = task_function(task_cfg)
117         ret.task_name = JobRuntime.instance().get("name")
118 
119         # shut down logging to ensure job log files are closed.
120         # If logging is still required after run_job caller is responsible to re-initialize it.
121         logging.shutdown()
122 
123         if config.hydra.output_subdir is not None:
124             hydra_output = Path(config.hydra.output_subdir)
125             _save_config(task_cfg, "config.yaml", hydra_output)
126             _save_config(hydra_cfg, "hydra.yaml", hydra_output)
127             _save_config(config.hydra.overrides.task, "overrides.yaml", hydra_output)
128 
129         return ret
130     finally:
131         os.chdir(old_cwd)
132 
133 
134 def get_valid_filename(s: str) -> str:
135     s = str(s).strip().replace(" ", "_")
136     return re.sub(r"(?u)[^-\w.]", "", s)
137 
138 
139 def setup_globals() -> None:
140     def register(name: str, f: Any) -> None:
141         try:
142             OmegaConf.register_resolver(name, f)
143         except AssertionError:
144             # calling it again in no_workers mode will throw. safe to ignore.
145             pass
146 
147     register("now", lambda pattern: strftime(pattern, localtime()))
148     register(
149         "hydra",
150         lambda path: OmegaConf.select(cast(DictConfig, HydraConfig.get()), path),
151     )
152 
153 
154 @dataclass
155 class JobReturn:
156     overrides: Optional[Sequence[str]] = None
157     return_value: Any = None
158     cfg: Optional[DictConfig] = None
159     hydra_cfg: Optional[DictConfig] = None
160     working_dir: Optional[str] = None
161     task_name: Optional[str] = None
162 
163 
164 class JobRuntime(metaclass=Singleton):
165     def __init__(self) -> None:
166         self.conf: DictConfig = OmegaConf.create()
167         self.set("name", "UNKNOWN_NAME")
168 
169     def get(self, key: str) -> Any:
170         ret = OmegaConf.select(self.conf, key)
171         if ret is None:
172             raise KeyError(f"Key not found in {type(self).__name__}: {key}")
173         return ret
174 
175     def set(self, key: str, value: Any) -> None:
176         log.debug(f"Setting {type(self).__name__}:{key}={value}")
177         self.conf[key] = value
178 
179 
180 def split_config_path(
181     config_path: Optional[str], config_name: Optional[str]
182 ) -> Tuple[Optional[str], Optional[str]]:
183     if config_path is None or config_path == "":
184         return None, config_name
185     split_file = splitext(config_path)
186     if split_file[1] in (".yaml", ".yml"):
187         # assuming dir/config.yaml form
188         config_file: Optional[str] = basename(config_path)
189         config_dir: Optional[str] = dirname(config_path)
190         msg = (
191             "\nUsing config_path to specify the config name is deprecated, specify the config name via config_name"
192             "\nSee https://hydra.cc/next/upgrades/0.11_to_1.0/config_path_changes"
193         )
194         warnings.warn(
195             category=UserWarning, message=msg,
196         )
197     else:
198         # assuming dir form without a config file.
199         config_file = None
200         config_dir = config_path
201 
202     if config_dir == "":
203         config_dir = None
204 
205     if config_file == "":
206         config_file = None
207 
208     if config_file is not None:
209         if config_name is not None:
210             raise ValueError(
211                 "Config name should be specified in either normalized_config_path or config_name, but not both"
212             )
213         config_name = config_file
214 
215     return config_dir, config_name
216 
217 
218 @contextmanager
219 def env_override(env: Dict[str, str]) -> Any:
220     """Temporarily set environment variables inside the context manager and
221     fully restore previous environment afterwards
222     """
223     original_env = {key: os.getenv(key) for key in env}
224     os.environ.update(env)
225     try:
226         yield
227     finally:
228         for key, value in original_env.items():
229             if value is None:
230                 del os.environ[key]
231             else:
232                 os.environ[key] = value
233
```
--- 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/hydra/core/utils.py b/hydra/core/utils.py
--- a/hydra/core/utils.py
+++ b/hydra/core/utils.py
@@ -112,6 +112,12 @@
         hydra_cfg = OmegaConf.masked_copy(config, "hydra")
         assert isinstance(hydra_cfg, DictConfig)
 
+        if config.hydra.output_subdir is not None:
+            hydra_output = Path(config.hydra.output_subdir)
+            _save_config(task_cfg, "config.yaml", hydra_output)
+            _save_config(hydra_cfg, "hydra.yaml", hydra_output)
+            _save_config(config.hydra.overrides.task, "overrides.yaml", hydra_output)
+
         with env_override(hydra_cfg.hydra.job.env_set):
             ret.return_value = task_function(task_cfg)
         ret.task_name = JobRuntime.instance().get("name")
@@ -120,12 +126,6 @@
         # If logging is still required after run_job caller is responsible to re-initialize it.
         logging.shutdown()
 
-        if config.hydra.output_subdir is not None:
-            hydra_output = Path(config.hydra.output_subdir)
-            _save_config(task_cfg, "config.yaml", hydra_output)
-            _save_config(hydra_cfg, "hydra.yaml", hydra_output)
-            _save_config(config.hydra.overrides.task, "overrides.yaml", hydra_output)
-
         return ret
     finally:
         os.chdir(old_cwd)

{"golden_diff": "diff --git a/hydra/core/utils.py b/hydra/core/utils.py\n--- a/hydra/core/utils.py\n+++ b/hydra/core/utils.py\n@@ -112,6 +112,12 @@\n         hydra_cfg = OmegaConf.masked_copy(config, \"hydra\")\n         assert isinstance(hydra_cfg, DictConfig)\n \n+        if config.hydra.output_subdir is not None:\n+            hydra_output = Path(config.hydra.output_subdir)\n+            _save_config(task_cfg, \"config.yaml\", hydra_output)\n+            _save_config(hydra_cfg, \"hydra.yaml\", hydra_output)\n+            _save_config(config.hydra.overrides.task, \"overrides.yaml\", hydra_output)\n+\n         with env_override(hydra_cfg.hydra.job.env_set):\n             ret.return_value = task_function(task_cfg)\n         ret.task_name = JobRuntime.instance().get(\"name\")\n@@ -120,12 +126,6 @@\n         # If logging is still required after run_job caller is responsible to re-initialize it.\n         logging.shutdown()\n \n-        if config.hydra.output_subdir is not None:\n-            hydra_output = Path(config.hydra.output_subdir)\n-            _save_config(task_cfg, \"config.yaml\", hydra_output)\n-            _save_config(hydra_cfg, \"hydra.yaml\", hydra_output)\n-            _save_config(config.hydra.overrides.task, \"overrides.yaml\", hydra_output)\n-\n         return ret\n     finally:\n         os.chdir(old_cwd)\n", "issue": "Save .hydra/*.yaml before task execution\n# \ud83d\udc1b Bug\r\n\r\nSaving the configurations is a really cool idea that helps me check what I actually did. I noticed the save timing is delayed after task execution in the `1.0.0rc1`. I have encountered some scenarios that I think it would be better if the configs are saved earlier.\r\n\r\nFor example,\r\n\r\n1. Tasks may exit accidentally due to bugs. Knowing detailed configurations would be helpful.\r\n2. For time-consuming tasks like ML training which may last for several days, it would be helpful to be able to check the config.yaml. This helps me a lot when I have multiple tasks running but I can't remember the real difference. I do `diff config.yaml`.\r\n3. Some tasks don't need to be finished. The full training may be designed to run 100 epochs but it also happens it's aborted/killed in the middle.\r\n\r\n## To reproduce\r\n\r\nDefault behavior in `1.0.0rc1`.\r\n\r\n** Minimal Code/Config snippet to reproduce **\r\nNA\r\n\r\n** Stack trace/error message **\r\nNA\r\n\r\n## Expected Behavior\r\nNA\r\n\r\n## System information\r\n- **Hydra Version** :  1.0.0rc1\r\n- **Python version** : NA\r\n- **Virtual environment type and version** : NA\r\n- **Operating system** : NA\r\n\r\n\n", "before_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved\nimport copy\nimport logging\nimport os\nimport re\nimport sys\nimport warnings\nfrom contextlib import contextmanager\nfrom dataclasses import dataclass\nfrom os.path import basename, dirname, splitext\nfrom pathlib import Path\nfrom time import localtime, strftime\nfrom typing import Any, Dict, Optional, Sequence, Tuple, Union, cast\n\nfrom omegaconf import DictConfig, OmegaConf, open_dict\n\nfrom hydra.core.hydra_config import HydraConfig\nfrom hydra.core.singleton import Singleton\nfrom hydra.types import TaskFunction\n\nlog = logging.getLogger(__name__)\n\n\ndef simple_stdout_log_config(level: int = logging.INFO) -> None:\n    root = logging.getLogger()\n    root.setLevel(level)\n    handler = logging.StreamHandler(sys.stdout)\n    formatter = logging.Formatter(\"%(message)s\")\n    handler.setFormatter(formatter)\n    root.addHandler(handler)\n\n\ndef configure_log(\n    log_config: DictConfig, verbose_config: Union[bool, str, Sequence[str]]\n) -> None:\n    assert isinstance(verbose_config, (bool, str)) or OmegaConf.is_list(verbose_config)\n    if log_config is not None:\n        conf: Dict[str, Any] = OmegaConf.to_container(  # type: ignore\n            log_config, resolve=True\n        )\n        logging.config.dictConfig(conf)\n    else:\n        # default logging to stdout\n        root = logging.getLogger()\n        root.setLevel(logging.INFO)\n        handler = logging.StreamHandler(sys.stdout)\n        formatter = logging.Formatter(\n            \"[%(asctime)s][%(name)s][%(levelname)s] - %(message)s\"\n        )\n        handler.setFormatter(formatter)\n        root.addHandler(handler)\n    if isinstance(verbose_config, bool):\n        if verbose_config:\n            logging.getLogger().setLevel(logging.DEBUG)\n    else:\n        if isinstance(verbose_config, str):\n            verbose_list = OmegaConf.create([verbose_config])\n        elif OmegaConf.is_list(verbose_config):\n            verbose_list = verbose_config  # type: ignore\n        else:\n            assert False\n\n        for logger in verbose_list:\n            logging.getLogger(logger).setLevel(logging.DEBUG)\n\n\ndef _save_config(cfg: DictConfig, filename: str, output_dir: Path) -> None:\n    output_dir.mkdir(parents=True, exist_ok=True)\n    with open(str(output_dir / filename), \"w\") as file:\n        file.write(cfg.pretty())\n\n\ndef filter_overrides(overrides: Sequence[str]) -> Sequence[str]:\n    \"\"\"\n    :param overrides: overrides list\n    :return: returning a new overrides list with all the keys starting with hydra. filtered.\n    \"\"\"\n    return [x for x in overrides if not x.startswith(\"hydra.\")]\n\n\ndef run_job(\n    config: DictConfig,\n    task_function: TaskFunction,\n    job_dir_key: str,\n    job_subdir_key: Optional[str],\n) -> \"JobReturn\":\n    old_cwd = os.getcwd()\n    working_dir = str(OmegaConf.select(config, job_dir_key))\n    if job_subdir_key is not None:\n        # evaluate job_subdir_key lazily.\n        # this is running on the client side in sweep and contains things such as job:id which\n        # are only available there.\n        subdir = str(OmegaConf.select(config, job_subdir_key))\n        working_dir = os.path.join(working_dir, subdir)\n    try:\n        ret = JobReturn()\n        ret.working_dir = working_dir\n        task_cfg = copy.deepcopy(config)\n        with open_dict(task_cfg):\n            del task_cfg[\"hydra\"]\n        ret.cfg = task_cfg\n        ret.hydra_cfg = OmegaConf.create({\"hydra\": HydraConfig.get()})\n        overrides = OmegaConf.to_container(config.hydra.overrides.task)\n        assert isinstance(overrides, list)\n        ret.overrides = overrides\n        # handle output directories here\n        Path(str(working_dir)).mkdir(parents=True, exist_ok=True)\n        os.chdir(working_dir)\n\n        configure_log(config.hydra.job_logging, config.hydra.verbose)\n\n        hydra_cfg = OmegaConf.masked_copy(config, \"hydra\")\n        assert isinstance(hydra_cfg, DictConfig)\n\n        with env_override(hydra_cfg.hydra.job.env_set):\n            ret.return_value = task_function(task_cfg)\n        ret.task_name = JobRuntime.instance().get(\"name\")\n\n        # shut down logging to ensure job log files are closed.\n        # If logging is still required after run_job caller is responsible to re-initialize it.\n        logging.shutdown()\n\n        if config.hydra.output_subdir is not None:\n            hydra_output = Path(config.hydra.output_subdir)\n            _save_config(task_cfg, \"config.yaml\", hydra_output)\n            _save_config(hydra_cfg, \"hydra.yaml\", hydra_output)\n            _save_config(config.hydra.overrides.task, \"overrides.yaml\", hydra_output)\n\n        return ret\n    finally:\n        os.chdir(old_cwd)\n\n\ndef get_valid_filename(s: str) -> str:\n    s = str(s).strip().replace(\" \", \"_\")\n    return re.sub(r\"(?u)[^-\\w.]\", \"\", s)\n\n\ndef setup_globals() -> None:\n    def register(name: str, f: Any) -> None:\n        try:\n            OmegaConf.register_resolver(name, f)\n        except AssertionError:\n            # calling it again in no_workers mode will throw. safe to ignore.\n            pass\n\n    register(\"now\", lambda pattern: strftime(pattern, localtime()))\n    register(\n        \"hydra\",\n        lambda path: OmegaConf.select(cast(DictConfig, HydraConfig.get()), path),\n    )\n\n\n@dataclass\nclass JobReturn:\n    overrides: Optional[Sequence[str]] = None\n    return_value: Any = None\n    cfg: Optional[DictConfig] = None\n    hydra_cfg: Optional[DictConfig] = None\n    working_dir: Optional[str] = None\n    task_name: Optional[str] = None\n\n\nclass JobRuntime(metaclass=Singleton):\n    def __init__(self) -> None:\n        self.conf: DictConfig = OmegaConf.create()\n        self.set(\"name\", \"UNKNOWN_NAME\")\n\n    def get(self, key: str) -> Any:\n        ret = OmegaConf.select(self.conf, key)\n        if ret is None:\n            raise KeyError(f\"Key not found in {type(self).__name__}: {key}\")\n        return ret\n\n    def set(self, key: str, value: Any) -> None:\n        log.debug(f\"Setting {type(self).__name__}:{key}={value}\")\n        self.conf[key] = value\n\n\ndef split_config_path(\n    config_path: Optional[str], config_name: Optional[str]\n) -> Tuple[Optional[str], Optional[str]]:\n    if config_path is None or config_path == \"\":\n        return None, config_name\n    split_file = splitext(config_path)\n    if split_file[1] in (\".yaml\", \".yml\"):\n        # assuming dir/config.yaml form\n        config_file: Optional[str] = basename(config_path)\n        config_dir: Optional[str] = dirname(config_path)\n        msg = (\n            \"\\nUsing config_path to specify the config name is deprecated, specify the config name via config_name\"\n            \"\\nSee https://hydra.cc/next/upgrades/0.11_to_1.0/config_path_changes\"\n        )\n        warnings.warn(\n            category=UserWarning, message=msg,\n        )\n    else:\n        # assuming dir form without a config file.\n        config_file = None\n        config_dir = config_path\n\n    if config_dir == \"\":\n        config_dir = None\n\n    if config_file == \"\":\n        config_file = None\n\n    if config_file is not None:\n        if config_name is not None:\n            raise ValueError(\n                \"Config name should be specified in either normalized_config_path or config_name, but not both\"\n            )\n        config_name = config_file\n\n    return config_dir, config_name\n\n\n@contextmanager\ndef env_override(env: Dict[str, str]) -> Any:\n    \"\"\"Temporarily set environment variables inside the context manager and\n    fully restore previous environment afterwards\n    \"\"\"\n    original_env = {key: os.getenv(key) for key in env}\n    os.environ.update(env)\n    try:\n        yield\n    finally:\n        for key, value in original_env.items():\n            if value is None:\n                del os.environ[key]\n            else:\n                os.environ[key] = value\n", "path": "hydra/core/utils.py"}], "after_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved\nimport copy\nimport logging\nimport os\nimport re\nimport sys\nimport warnings\nfrom contextlib import contextmanager\nfrom dataclasses import dataclass\nfrom os.path import basename, dirname, splitext\nfrom pathlib import Path\nfrom time import localtime, strftime\nfrom typing import Any, Dict, Optional, Sequence, Tuple, Union, cast\n\nfrom omegaconf import DictConfig, OmegaConf, open_dict\n\nfrom hydra.core.hydra_config import HydraConfig\nfrom hydra.core.singleton import Singleton\nfrom hydra.types import TaskFunction\n\nlog = logging.getLogger(__name__)\n\n\ndef simple_stdout_log_config(level: int = logging.INFO) -> None:\n    root = logging.getLogger()\n    root.setLevel(level)\n    handler = logging.StreamHandler(sys.stdout)\n    formatter = logging.Formatter(\"%(message)s\")\n    handler.setFormatter(formatter)\n    root.addHandler(handler)\n\n\ndef configure_log(\n    log_config: DictConfig, verbose_config: Union[bool, str, Sequence[str]]\n) -> None:\n    assert isinstance(verbose_config, (bool, str)) or OmegaConf.is_list(verbose_config)\n    if log_config is not None:\n        conf: Dict[str, Any] = OmegaConf.to_container(  # type: ignore\n            log_config, resolve=True\n        )\n        logging.config.dictConfig(conf)\n    else:\n        # default logging to stdout\n        root = logging.getLogger()\n        root.setLevel(logging.INFO)\n        handler = logging.StreamHandler(sys.stdout)\n        formatter = logging.Formatter(\n            \"[%(asctime)s][%(name)s][%(levelname)s] - %(message)s\"\n        )\n        handler.setFormatter(formatter)\n        root.addHandler(handler)\n    if isinstance(verbose_config, bool):\n        if verbose_config:\n            logging.getLogger().setLevel(logging.DEBUG)\n    else:\n        if isinstance(verbose_config, str):\n            verbose_list = OmegaConf.create([verbose_config])\n        elif OmegaConf.is_list(verbose_config):\n            verbose_list = verbose_config  # type: ignore\n        else:\n            assert False\n\n        for logger in verbose_list:\n            logging.getLogger(logger).setLevel(logging.DEBUG)\n\n\ndef _save_config(cfg: DictConfig, filename: str, output_dir: Path) -> None:\n    output_dir.mkdir(parents=True, exist_ok=True)\n    with open(str(output_dir / filename), \"w\") as file:\n        file.write(cfg.pretty())\n\n\ndef filter_overrides(overrides: Sequence[str]) -> Sequence[str]:\n    \"\"\"\n    :param overrides: overrides list\n    :return: returning a new overrides list with all the keys starting with hydra. filtered.\n    \"\"\"\n    return [x for x in overrides if not x.startswith(\"hydra.\")]\n\n\ndef run_job(\n    config: DictConfig,\n    task_function: TaskFunction,\n    job_dir_key: str,\n    job_subdir_key: Optional[str],\n) -> \"JobReturn\":\n    old_cwd = os.getcwd()\n    working_dir = str(OmegaConf.select(config, job_dir_key))\n    if job_subdir_key is not None:\n        # evaluate job_subdir_key lazily.\n        # this is running on the client side in sweep and contains things such as job:id which\n        # are only available there.\n        subdir = str(OmegaConf.select(config, job_subdir_key))\n        working_dir = os.path.join(working_dir, subdir)\n    try:\n        ret = JobReturn()\n        ret.working_dir = working_dir\n        task_cfg = copy.deepcopy(config)\n        with open_dict(task_cfg):\n            del task_cfg[\"hydra\"]\n        ret.cfg = task_cfg\n        ret.hydra_cfg = OmegaConf.create({\"hydra\": HydraConfig.get()})\n        overrides = OmegaConf.to_container(config.hydra.overrides.task)\n        assert isinstance(overrides, list)\n        ret.overrides = overrides\n        # handle output directories here\n        Path(str(working_dir)).mkdir(parents=True, exist_ok=True)\n        os.chdir(working_dir)\n\n        configure_log(config.hydra.job_logging, config.hydra.verbose)\n\n        hydra_cfg = OmegaConf.masked_copy(config, \"hydra\")\n        assert isinstance(hydra_cfg, DictConfig)\n\n        if config.hydra.output_subdir is not None:\n            hydra_output = Path(config.hydra.output_subdir)\n            _save_config(task_cfg, \"config.yaml\", hydra_output)\n            _save_config(hydra_cfg, \"hydra.yaml\", hydra_output)\n            _save_config(config.hydra.overrides.task, \"overrides.yaml\", hydra_output)\n\n        with env_override(hydra_cfg.hydra.job.env_set):\n            ret.return_value = task_function(task_cfg)\n        ret.task_name = JobRuntime.instance().get(\"name\")\n\n        # shut down logging to ensure job log files are closed.\n        # If logging is still required after run_job caller is responsible to re-initialize it.\n        logging.shutdown()\n\n        return ret\n    finally:\n        os.chdir(old_cwd)\n\n\ndef get_valid_filename(s: str) -> str:\n    s = str(s).strip().replace(\" \", \"_\")\n    return re.sub(r\"(?u)[^-\\w.]\", \"\", s)\n\n\ndef setup_globals() -> None:\n    def register(name: str, f: Any) -> None:\n        try:\n            OmegaConf.register_resolver(name, f)\n        except AssertionError:\n            # calling it again in no_workers mode will throw. safe to ignore.\n            pass\n\n    register(\"now\", lambda pattern: strftime(pattern, localtime()))\n    register(\n        \"hydra\",\n        lambda path: OmegaConf.select(cast(DictConfig, HydraConfig.get()), path),\n    )\n\n\n@dataclass\nclass JobReturn:\n    overrides: Optional[Sequence[str]] = None\n    return_value: Any = None\n    cfg: Optional[DictConfig] = None\n    hydra_cfg: Optional[DictConfig] = None\n    working_dir: Optional[str] = None\n    task_name: Optional[str] = None\n\n\nclass JobRuntime(metaclass=Singleton):\n    def __init__(self) -> None:\n        self.conf: DictConfig = OmegaConf.create()\n        self.set(\"name\", \"UNKNOWN_NAME\")\n\n    def get(self, key: str) -> Any:\n        ret = OmegaConf.select(self.conf, key)\n        if ret is None:\n            raise KeyError(f\"Key not found in {type(self).__name__}: {key}\")\n        return ret\n\n    def set(self, key: str, value: Any) -> None:\n        log.debug(f\"Setting {type(self).__name__}:{key}={value}\")\n        self.conf[key] = value\n\n\ndef split_config_path(\n    config_path: Optional[str], config_name: Optional[str]\n) -> Tuple[Optional[str], Optional[str]]:\n    if config_path is None or config_path == \"\":\n        return None, config_name\n    split_file = splitext(config_path)\n    if split_file[1] in (\".yaml\", \".yml\"):\n        # assuming dir/config.yaml form\n        config_file: Optional[str] = basename(config_path)\n        config_dir: Optional[str] = dirname(config_path)\n        msg = (\n            \"\\nUsing config_path to specify the config name is deprecated, specify the config name via config_name\"\n            \"\\nSee https://hydra.cc/next/upgrades/0.11_to_1.0/config_path_changes\"\n        )\n        warnings.warn(\n            category=UserWarning, message=msg,\n        )\n    else:\n        # assuming dir form without a config file.\n        config_file = None\n        config_dir = config_path\n\n    if config_dir == \"\":\n        config_dir = None\n\n    if config_file == \"\":\n        config_file = None\n\n    if config_file is not None:\n        if config_name is not None:\n            raise ValueError(\n                \"Config name should be specified in either normalized_config_path or config_name, but not both\"\n            )\n        config_name = config_file\n\n    return config_dir, config_name\n\n\n@contextmanager\ndef env_override(env: Dict[str, str]) -> Any:\n    \"\"\"Temporarily set environment variables inside the context manager and\n    fully restore previous environment afterwards\n    \"\"\"\n    original_env = {key: os.getenv(key) for key in env}\n    os.environ.update(env)\n    try:\n        yield\n    finally:\n        for key, value in original_env.items():\n            if value is None:\n                del os.environ[key]\n            else:\n                os.environ[key] = value\n", "path": "hydra/core/utils.py"}]}