We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Bug] hydra.job.id and hydra.job.num are not properly transferred to jobs in multirun


--- 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, read_write
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(OmegaConf.to_yaml(cfg))
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     configure_logging: bool = True,
87 ) -> "JobReturn":
88     old_cwd = os.getcwd()
89     working_dir = str(OmegaConf.select(config, job_dir_key))
90     if job_subdir_key is not None:
91         # evaluate job_subdir_key lazily.
92         # this is running on the client side in sweep and contains things such as job:id which
93         # are only available there.
94         subdir = str(OmegaConf.select(config, job_subdir_key))
95         working_dir = os.path.join(working_dir, subdir)
96     try:
97         ret = JobReturn()
98         ret.working_dir = working_dir
99         task_cfg = copy.deepcopy(config)
100         with read_write(task_cfg):
101             with open_dict(task_cfg):
102                 del task_cfg["hydra"]
103         ret.cfg = task_cfg
104         ret.hydra_cfg = OmegaConf.create({"hydra": HydraConfig.get()})
105         overrides = OmegaConf.to_container(config.hydra.overrides.task)
106         assert isinstance(overrides, list)
107         ret.overrides = overrides
108         # handle output directories here
109         Path(str(working_dir)).mkdir(parents=True, exist_ok=True)
110         os.chdir(working_dir)
111 
112         if configure_logging:
113             configure_log(config.hydra.job_logging, config.hydra.verbose)
114 
115         hydra_cfg = OmegaConf.masked_copy(config, "hydra")
116         assert isinstance(hydra_cfg, DictConfig)
117 
118         if config.hydra.output_subdir is not None:
119             hydra_output = Path(config.hydra.output_subdir)
120             _save_config(task_cfg, "config.yaml", hydra_output)
121             _save_config(hydra_cfg, "hydra.yaml", hydra_output)
122             _save_config(config.hydra.overrides.task, "overrides.yaml", hydra_output)
123 
124         with env_override(hydra_cfg.hydra.job.env_set):
125             ret.return_value = task_function(task_cfg)
126         ret.task_name = JobRuntime.instance().get("name")
127 
128         _flush_loggers()
129 
130         return ret
131     finally:
132         os.chdir(old_cwd)
133 
134 
135 def get_valid_filename(s: str) -> str:
136     s = str(s).strip().replace(" ", "_")
137     return re.sub(r"(?u)[^-\w.]", "", s)
138 
139 
140 def setup_globals() -> None:
141     def register(name: str, f: Any) -> None:
142         try:
143             OmegaConf.register_resolver(name, f)
144         except AssertionError:
145             # calling it again in no_workers mode will throw. safe to ignore.
146             pass
147 
148     # please add documentation when you add a new resolver
149     register("now", lambda pattern: strftime(pattern, localtime()))
150     register(
151         "hydra",
152         lambda path: OmegaConf.select(cast(DictConfig, HydraConfig.get()), path),
153     )
154 
155     vi = sys.version_info
156     version_dict = {
157         "major": f"{vi[0]}",
158         "minor": f"{vi[0]}.{vi[1]}",
159         "micro": f"{vi[0]}.{vi[1]}.{vi[2]}",
160     }
161     register("python_version", lambda level="minor": version_dict.get(level))
162 
163 
164 @dataclass
165 class JobReturn:
166     overrides: Optional[Sequence[str]] = None
167     return_value: Any = None
168     cfg: Optional[DictConfig] = None
169     hydra_cfg: Optional[DictConfig] = None
170     working_dir: Optional[str] = None
171     task_name: Optional[str] = None
172 
173 
174 class JobRuntime(metaclass=Singleton):
175     def __init__(self) -> None:
176         self.conf: DictConfig = OmegaConf.create()
177         self.set("name", "UNKNOWN_NAME")
178 
179     def get(self, key: str) -> Any:
180         ret = OmegaConf.select(self.conf, key)
181         if ret is None:
182             raise KeyError(f"Key not found in {type(self).__name__}: {key}")
183         return ret
184 
185     def set(self, key: str, value: Any) -> None:
186         log.debug(f"Setting {type(self).__name__}:{key}={value}")
187         self.conf[key] = value
188 
189 
190 def split_config_path(
191     config_path: Optional[str], config_name: Optional[str]
192 ) -> Tuple[Optional[str], Optional[str]]:
193     if config_path is None or config_path == "":
194         return None, config_name
195     split_file = splitext(config_path)
196     if split_file[1] in (".yaml", ".yml"):
197         # assuming dir/config.yaml form
198         config_file: Optional[str] = basename(config_path)
199         config_dir: Optional[str] = dirname(config_path)
200         msg = (
201             "\nUsing config_path to specify the config name is deprecated, specify the config name via config_name"
202             "\nSee https://hydra.cc/docs/next/upgrades/0.11_to_1.0/config_path_changes"
203         )
204         warnings.warn(category=UserWarning, message=msg)
205     else:
206         # assuming dir form without a config file.
207         config_file = None
208         config_dir = config_path
209 
210     if config_dir == "":
211         config_dir = None
212 
213     if config_file == "":
214         config_file = None
215 
216     if config_file is not None:
217         if config_name is not None:
218             raise ValueError(
219                 "Config name should be specified in either normalized_config_path or config_name, but not both"
220             )
221         config_name = config_file
222 
223     return config_dir, config_name
224 
225 
226 @contextmanager
227 def env_override(env: Dict[str, str]) -> Any:
228     """Temporarily set environment variables inside the context manager and
229     fully restore previous environment afterwards
230     """
231     original_env = {key: os.getenv(key) for key in env}
232     os.environ.update(env)
233     try:
234         yield
235     finally:
236         for key, value in original_env.items():
237             if value is None:
238                 del os.environ[key]
239             else:
240                 os.environ[key] = value
241 
242 
243 def _flush_loggers() -> None:
244     # Python logging does not have an official API to flush all loggers.
245     # This will have to do.
246     for h_weak_ref in logging._handlerList:  # type: ignore
247         try:
248             h_weak_ref().flush()
249         except Exception:
250             # ignore exceptions thrown during flushing
251             pass
252
```
--- 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
@@ -87,6 +87,7 @@
 ) -> "JobReturn":
     old_cwd = os.getcwd()
     working_dir = str(OmegaConf.select(config, job_dir_key))
+    orig_hydra_cfg = HydraConfig.instance().cfg
     if job_subdir_key is not None:
         # evaluate job_subdir_key lazily.
         # this is running on the client side in sweep and contains things such as job:id which
@@ -97,11 +98,16 @@
         ret = JobReturn()
         ret.working_dir = working_dir
         task_cfg = copy.deepcopy(config)
+        hydra_cfg = OmegaConf.masked_copy(task_cfg, "hydra")
+        # maintain parent to preserve interpolation links from hydra_cfg to job_cfg
+        hydra_cfg._set_parent(task_cfg)
         with read_write(task_cfg):
             with open_dict(task_cfg):
                 del task_cfg["hydra"]
+        HydraConfig.instance().cfg = hydra_cfg  # type: ignore
+
         ret.cfg = task_cfg
-        ret.hydra_cfg = OmegaConf.create({"hydra": HydraConfig.get()})
+        ret.hydra_cfg = hydra_cfg
         overrides = OmegaConf.to_container(config.hydra.overrides.task)
         assert isinstance(overrides, list)
         ret.overrides = overrides
@@ -112,9 +118,6 @@
         if configure_logging:
             configure_log(config.hydra.job_logging, config.hydra.verbose)
 
-        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)
@@ -129,6 +132,7 @@
 
         return ret
     finally:
+        HydraConfig.instance().cfg = orig_hydra_cfg
         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@@ -87,6 +87,7 @@\n ) -> \"JobReturn\":\n     old_cwd = os.getcwd()\n     working_dir = str(OmegaConf.select(config, job_dir_key))\n+    orig_hydra_cfg = HydraConfig.instance().cfg\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@@ -97,11 +98,16 @@\n         ret = JobReturn()\n         ret.working_dir = working_dir\n         task_cfg = copy.deepcopy(config)\n+        hydra_cfg = OmegaConf.masked_copy(task_cfg, \"hydra\")\n+        # maintain parent to preserve interpolation links from hydra_cfg to job_cfg\n+        hydra_cfg._set_parent(task_cfg)\n         with read_write(task_cfg):\n             with open_dict(task_cfg):\n                 del task_cfg[\"hydra\"]\n+        HydraConfig.instance().cfg = hydra_cfg  # type: ignore\n+\n         ret.cfg = task_cfg\n-        ret.hydra_cfg = OmegaConf.create({\"hydra\": HydraConfig.get()})\n+        ret.hydra_cfg = hydra_cfg\n         overrides = OmegaConf.to_container(config.hydra.overrides.task)\n         assert isinstance(overrides, list)\n         ret.overrides = overrides\n@@ -112,9 +118,6 @@\n         if configure_logging:\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@@ -129,6 +132,7 @@\n \n         return ret\n     finally:\n+        HydraConfig.instance().cfg = orig_hydra_cfg\n         os.chdir(old_cwd)\n", "issue": "[Bug] hydra.job.id and hydra.job.num are not properly transferred to jobs in multirun\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, read_write\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(OmegaConf.to_yaml(cfg))\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    configure_logging: bool = True,\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 read_write(task_cfg):\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        if configure_logging:\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        _flush_loggers()\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    # please add documentation when you add a new resolver\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    vi = sys.version_info\n    version_dict = {\n        \"major\": f\"{vi[0]}\",\n        \"minor\": f\"{vi[0]}.{vi[1]}\",\n        \"micro\": f\"{vi[0]}.{vi[1]}.{vi[2]}\",\n    }\n    register(\"python_version\", lambda level=\"minor\": version_dict.get(level))\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/docs/next/upgrades/0.11_to_1.0/config_path_changes\"\n        )\n        warnings.warn(category=UserWarning, message=msg)\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\n\ndef _flush_loggers() -> None:\n    # Python logging does not have an official API to flush all loggers.\n    # This will have to do.\n    for h_weak_ref in logging._handlerList:  # type: ignore\n        try:\n            h_weak_ref().flush()\n        except Exception:\n            # ignore exceptions thrown during flushing\n            pass\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, read_write\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(OmegaConf.to_yaml(cfg))\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    configure_logging: bool = True,\n) -> \"JobReturn\":\n    old_cwd = os.getcwd()\n    working_dir = str(OmegaConf.select(config, job_dir_key))\n    orig_hydra_cfg = HydraConfig.instance().cfg\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        hydra_cfg = OmegaConf.masked_copy(task_cfg, \"hydra\")\n        # maintain parent to preserve interpolation links from hydra_cfg to job_cfg\n        hydra_cfg._set_parent(task_cfg)\n        with read_write(task_cfg):\n            with open_dict(task_cfg):\n                del task_cfg[\"hydra\"]\n        HydraConfig.instance().cfg = hydra_cfg  # type: ignore\n\n        ret.cfg = task_cfg\n        ret.hydra_cfg = hydra_cfg\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        if configure_logging:\n            configure_log(config.hydra.job_logging, config.hydra.verbose)\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        _flush_loggers()\n\n        return ret\n    finally:\n        HydraConfig.instance().cfg = orig_hydra_cfg\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    # please add documentation when you add a new resolver\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    vi = sys.version_info\n    version_dict = {\n        \"major\": f\"{vi[0]}\",\n        \"minor\": f\"{vi[0]}.{vi[1]}\",\n        \"micro\": f\"{vi[0]}.{vi[1]}.{vi[2]}\",\n    }\n    register(\"python_version\", lambda level=\"minor\": version_dict.get(level))\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/docs/next/upgrades/0.11_to_1.0/config_path_changes\"\n        )\n        warnings.warn(category=UserWarning, message=msg)\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\n\ndef _flush_loggers() -> None:\n    # Python logging does not have an official API to flush all loggers.\n    # This will have to do.\n    for h_weak_ref in logging._handlerList:  # type: ignore\n        try:\n            h_weak_ref().flush()\n        except Exception:\n            # ignore exceptions thrown during flushing\n            pass\n", "path": "hydra/core/utils.py"}]}