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