We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Tune] Experiment Analysis get_best behaviour
Hi,
In their current version, the [`get_best_config`](https://github.com/ray-project/ray/blob/ed89897a311fbe63afdd5fa05a4ef8b7576ca6a4/python/ray/tune/analysis/experiment_analysis.py#L56) and [`get_best_logdir`](https://github.com/ray-project/ray/blob/ed89897a311fbe63afdd5fa05a4ef8b7576ca6a4/python/ray/tune/analysis/experiment_analysis.py#L70) methods of the `Analysis` object may consider different Trials as the best one:
- `get_best_config` will first retrieve the best row of each trial dataframe and then select the best trial from these rows.
- `get_best_logdir` will first retrieve the last row of each trial and then selects the best one.

Is it the expected behaviour ? 
If it isn't, I think that the correct way of doing it is the first one. This could be done by simply passing the `metric` and `max` arguments to the [`self.dataframe`](https://github.com/ray-project/ray/blob/ed89897a311fbe63afdd5fa05a4ef8b7576ca6a4/python/ray/tune/analysis/experiment_analysis.py#L78) call in `get_best_dir`.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `python/ray/tune/analysis/experiment_analysis.py`
Content:
```
1 from __future__ import absolute_import
2 from __future__ import division
3 from __future__ import print_function
4 
5 import json
6 import logging
7 import os
8 
9 try:
10     import pandas as pd
11 except ImportError:
12     pd = None
13 
14 from ray.tune.error import TuneError
15 from ray.tune.result import EXPR_PROGRESS_FILE, EXPR_PARAM_FILE, CONFIG_PREFIX
16 
17 logger = logging.getLogger(__name__)
18 
19 
20 class Analysis(object):
21     """Analyze all results from a directory of experiments."""
22 
23     def __init__(self, experiment_dir):
24         experiment_dir = os.path.expanduser(experiment_dir)
25         if not os.path.isdir(experiment_dir):
26             raise ValueError(
27                 "{} is not a valid directory.".format(experiment_dir))
28         self._experiment_dir = experiment_dir
29         self._configs = {}
30         self._trial_dataframes = {}
31 
32         if not pd:
33             logger.warning(
34                 "pandas not installed. Run `pip install pandas` for "
35                 "Analysis utilities.")
36         else:
37             self.fetch_trial_dataframes()
38 
39     def dataframe(self, metric=None, mode=None):
40         """Returns a pandas.DataFrame object constructed from the trials.
41 
42         Args:
43             metric (str): Key for trial info to order on.
44                 If None, uses last result.
45             mode (str): One of [min, max].
46 
47         """
48         rows = self._retrieve_rows(metric=metric, mode=mode)
49         all_configs = self.get_all_configs(prefix=True)
50         for path, config in all_configs.items():
51             if path in rows:
52                 rows[path].update(config)
53                 rows[path].update(logdir=path)
54         return pd.DataFrame(list(rows.values()))
55 
56     def get_best_config(self, metric, mode="max"):
57         """Retrieve the best config corresponding to the trial.
58 
59         Args:
60             metric (str): Key for trial info to order on.
61             mode (str): One of [min, max].
62 
63         """
64         rows = self._retrieve_rows(metric=metric, mode=mode)
65         all_configs = self.get_all_configs()
66         compare_op = max if mode == "max" else min
67         best_path = compare_op(rows, key=lambda k: rows[k][metric])
68         return all_configs[best_path]
69 
70     def get_best_logdir(self, metric, mode="max"):
71         """Retrieve the logdir corresponding to the best trial.
72 
73         Args:
74             metric (str): Key for trial info to order on.
75             mode (str): One of [min, max].
76 
77         """
78         df = self.dataframe()
79         if mode == "max":
80             return df.iloc[df[metric].idxmax()].logdir
81         elif mode == "min":
82             return df.iloc[df[metric].idxmin()].logdir
83 
84     def fetch_trial_dataframes(self):
85         fail_count = 0
86         for path in self._get_trial_paths():
87             try:
88                 self.trial_dataframes[path] = pd.read_csv(
89                     os.path.join(path, EXPR_PROGRESS_FILE))
90             except Exception:
91                 fail_count += 1
92 
93         if fail_count:
94             logger.debug(
95                 "Couldn't read results from {} paths".format(fail_count))
96         return self.trial_dataframes
97 
98     def get_all_configs(self, prefix=False):
99         """Returns a list of all configurations.
100 
101         Parameters:
102             prefix (bool): If True, flattens the config dict
103                 and prepends `config/`.
104         """
105         fail_count = 0
106         for path in self._get_trial_paths():
107             try:
108                 with open(os.path.join(path, EXPR_PARAM_FILE)) as f:
109                     config = json.load(f)
110                     if prefix:
111                         for k in list(config):
112                             config[CONFIG_PREFIX + k] = config.pop(k)
113                     self._configs[path] = config
114             except Exception:
115                 fail_count += 1
116 
117         if fail_count:
118             logger.warning(
119                 "Couldn't read config from {} paths".format(fail_count))
120         return self._configs
121 
122     def _retrieve_rows(self, metric=None, mode=None):
123         assert mode is None or mode in ["max", "min"]
124         rows = {}
125         for path, df in self.trial_dataframes.items():
126             if mode == "max":
127                 idx = df[metric].idxmax()
128             elif mode == "min":
129                 idx = df[metric].idxmin()
130             else:
131                 idx = -1
132             rows[path] = df.iloc[idx].to_dict()
133 
134         return rows
135 
136     def _get_trial_paths(self):
137         _trial_paths = []
138         for trial_path, _, files in os.walk(self._experiment_dir):
139             if EXPR_PROGRESS_FILE in files:
140                 _trial_paths += [trial_path]
141 
142         if not _trial_paths:
143             raise TuneError("No trials found in {}.".format(
144                 self._experiment_dir))
145         return _trial_paths
146 
147     @property
148     def trial_dataframes(self):
149         """List of all dataframes of the trials."""
150         return self._trial_dataframes
151 
152 
153 class ExperimentAnalysis(Analysis):
154     """Analyze results from a Tune experiment.
155 
156     Parameters:
157         experiment_checkpoint_path (str): Path to a json file
158             representing an experiment state. Corresponds to
159             Experiment.local_dir/Experiment.name/experiment_state.json
160 
161     Example:
162         >>> tune.run(my_trainable, name="my_exp", local_dir="~/tune_results")
163         >>> analysis = ExperimentAnalysis(
164         >>>     experiment_checkpoint_path="~/tune_results/my_exp/state.json")
165     """
166 
167     def __init__(self, experiment_checkpoint_path, trials=None):
168         """Initializer.
169 
170         Args:
171             experiment_path (str): Path to where experiment is located.
172             trials (list|None): List of trials that can be accessed via
173                 `analysis.trials`.
174         """
175         with open(experiment_checkpoint_path) as f:
176             _experiment_state = json.load(f)
177             self._experiment_state = _experiment_state
178 
179         if "checkpoints" not in _experiment_state:
180             raise TuneError("Experiment state invalid; no checkpoints found.")
181         self._checkpoints = _experiment_state["checkpoints"]
182         self.trials = trials
183         super(ExperimentAnalysis, self).__init__(
184             os.path.dirname(experiment_checkpoint_path))
185 
186     def stats(self):
187         """Returns a dictionary of the statistics of the experiment."""
188         return self._experiment_state.get("stats")
189 
190     def runner_data(self):
191         """Returns a dictionary of the TrialRunner data."""
192         return self._experiment_state.get("runner_data")
193 
194     def _get_trial_paths(self):
195         """Overwrites Analysis to only have trials of one experiment."""
196         if self.trials:
197             _trial_paths = [t.logdir for t in self.trials]
198         else:
199             logger.warning("No `self.trials`. Drawing logdirs from checkpoint "
200                            "file. This may result in some information that is "
201                            "out of sync, as checkpointing is periodic.")
202             _trial_paths = [
203                 checkpoint["logdir"] for checkpoint in self._checkpoints
204             ]
205         if not _trial_paths:
206             raise TuneError("No trials found.")
207         return _trial_paths
208
```
--- 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/python/ray/tune/analysis/experiment_analysis.py b/python/ray/tune/analysis/experiment_analysis.py
--- a/python/ray/tune/analysis/experiment_analysis.py
+++ b/python/ray/tune/analysis/experiment_analysis.py
@@ -75,7 +75,7 @@
             mode (str): One of [min, max].
 
         """
-        df = self.dataframe()
+        df = self.dataframe(metric=metric, mode=mode)
         if mode == "max":
             return df.iloc[df[metric].idxmax()].logdir
         elif mode == "min":

{"golden_diff": "diff --git a/python/ray/tune/analysis/experiment_analysis.py b/python/ray/tune/analysis/experiment_analysis.py\n--- a/python/ray/tune/analysis/experiment_analysis.py\n+++ b/python/ray/tune/analysis/experiment_analysis.py\n@@ -75,7 +75,7 @@\n             mode (str): One of [min, max].\n \n         \"\"\"\n-        df = self.dataframe()\n+        df = self.dataframe(metric=metric, mode=mode)\n         if mode == \"max\":\n             return df.iloc[df[metric].idxmax()].logdir\n         elif mode == \"min\":\n", "issue": "[Tune] Experiment Analysis get_best behaviour\nHi,\r\nIn their current version, the [`get_best_config`](https://github.com/ray-project/ray/blob/ed89897a311fbe63afdd5fa05a4ef8b7576ca6a4/python/ray/tune/analysis/experiment_analysis.py#L56) and [`get_best_logdir`](https://github.com/ray-project/ray/blob/ed89897a311fbe63afdd5fa05a4ef8b7576ca6a4/python/ray/tune/analysis/experiment_analysis.py#L70) methods of the `Analysis` object may consider different Trials as the best one:\r\n- `get_best_config` will first retrieve the best row of each trial dataframe and then select the best trial from these rows.\r\n- `get_best_logdir` will first retrieve the last row of each trial and then selects the best one.\r\n\r\nIs it the expected behaviour ? \r\nIf it isn't, I think that the correct way of doing it is the first one. This could be done by simply passing the `metric` and `max` arguments to the [`self.dataframe`](https://github.com/ray-project/ray/blob/ed89897a311fbe63afdd5fa05a4ef8b7576ca6a4/python/ray/tune/analysis/experiment_analysis.py#L78) call in `get_best_dir`.\r\n\r\n\n", "before_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport json\nimport logging\nimport os\n\ntry:\n    import pandas as pd\nexcept ImportError:\n    pd = None\n\nfrom ray.tune.error import TuneError\nfrom ray.tune.result import EXPR_PROGRESS_FILE, EXPR_PARAM_FILE, CONFIG_PREFIX\n\nlogger = logging.getLogger(__name__)\n\n\nclass Analysis(object):\n    \"\"\"Analyze all results from a directory of experiments.\"\"\"\n\n    def __init__(self, experiment_dir):\n        experiment_dir = os.path.expanduser(experiment_dir)\n        if not os.path.isdir(experiment_dir):\n            raise ValueError(\n                \"{} is not a valid directory.\".format(experiment_dir))\n        self._experiment_dir = experiment_dir\n        self._configs = {}\n        self._trial_dataframes = {}\n\n        if not pd:\n            logger.warning(\n                \"pandas not installed. Run `pip install pandas` for \"\n                \"Analysis utilities.\")\n        else:\n            self.fetch_trial_dataframes()\n\n    def dataframe(self, metric=None, mode=None):\n        \"\"\"Returns a pandas.DataFrame object constructed from the trials.\n\n        Args:\n            metric (str): Key for trial info to order on.\n                If None, uses last result.\n            mode (str): One of [min, max].\n\n        \"\"\"\n        rows = self._retrieve_rows(metric=metric, mode=mode)\n        all_configs = self.get_all_configs(prefix=True)\n        for path, config in all_configs.items():\n            if path in rows:\n                rows[path].update(config)\n                rows[path].update(logdir=path)\n        return pd.DataFrame(list(rows.values()))\n\n    def get_best_config(self, metric, mode=\"max\"):\n        \"\"\"Retrieve the best config corresponding to the trial.\n\n        Args:\n            metric (str): Key for trial info to order on.\n            mode (str): One of [min, max].\n\n        \"\"\"\n        rows = self._retrieve_rows(metric=metric, mode=mode)\n        all_configs = self.get_all_configs()\n        compare_op = max if mode == \"max\" else min\n        best_path = compare_op(rows, key=lambda k: rows[k][metric])\n        return all_configs[best_path]\n\n    def get_best_logdir(self, metric, mode=\"max\"):\n        \"\"\"Retrieve the logdir corresponding to the best trial.\n\n        Args:\n            metric (str): Key for trial info to order on.\n            mode (str): One of [min, max].\n\n        \"\"\"\n        df = self.dataframe()\n        if mode == \"max\":\n            return df.iloc[df[metric].idxmax()].logdir\n        elif mode == \"min\":\n            return df.iloc[df[metric].idxmin()].logdir\n\n    def fetch_trial_dataframes(self):\n        fail_count = 0\n        for path in self._get_trial_paths():\n            try:\n                self.trial_dataframes[path] = pd.read_csv(\n                    os.path.join(path, EXPR_PROGRESS_FILE))\n            except Exception:\n                fail_count += 1\n\n        if fail_count:\n            logger.debug(\n                \"Couldn't read results from {} paths\".format(fail_count))\n        return self.trial_dataframes\n\n    def get_all_configs(self, prefix=False):\n        \"\"\"Returns a list of all configurations.\n\n        Parameters:\n            prefix (bool): If True, flattens the config dict\n                and prepends `config/`.\n        \"\"\"\n        fail_count = 0\n        for path in self._get_trial_paths():\n            try:\n                with open(os.path.join(path, EXPR_PARAM_FILE)) as f:\n                    config = json.load(f)\n                    if prefix:\n                        for k in list(config):\n                            config[CONFIG_PREFIX + k] = config.pop(k)\n                    self._configs[path] = config\n            except Exception:\n                fail_count += 1\n\n        if fail_count:\n            logger.warning(\n                \"Couldn't read config from {} paths\".format(fail_count))\n        return self._configs\n\n    def _retrieve_rows(self, metric=None, mode=None):\n        assert mode is None or mode in [\"max\", \"min\"]\n        rows = {}\n        for path, df in self.trial_dataframes.items():\n            if mode == \"max\":\n                idx = df[metric].idxmax()\n            elif mode == \"min\":\n                idx = df[metric].idxmin()\n            else:\n                idx = -1\n            rows[path] = df.iloc[idx].to_dict()\n\n        return rows\n\n    def _get_trial_paths(self):\n        _trial_paths = []\n        for trial_path, _, files in os.walk(self._experiment_dir):\n            if EXPR_PROGRESS_FILE in files:\n                _trial_paths += [trial_path]\n\n        if not _trial_paths:\n            raise TuneError(\"No trials found in {}.\".format(\n                self._experiment_dir))\n        return _trial_paths\n\n    @property\n    def trial_dataframes(self):\n        \"\"\"List of all dataframes of the trials.\"\"\"\n        return self._trial_dataframes\n\n\nclass ExperimentAnalysis(Analysis):\n    \"\"\"Analyze results from a Tune experiment.\n\n    Parameters:\n        experiment_checkpoint_path (str): Path to a json file\n            representing an experiment state. Corresponds to\n            Experiment.local_dir/Experiment.name/experiment_state.json\n\n    Example:\n        >>> tune.run(my_trainable, name=\"my_exp\", local_dir=\"~/tune_results\")\n        >>> analysis = ExperimentAnalysis(\n        >>>     experiment_checkpoint_path=\"~/tune_results/my_exp/state.json\")\n    \"\"\"\n\n    def __init__(self, experiment_checkpoint_path, trials=None):\n        \"\"\"Initializer.\n\n        Args:\n            experiment_path (str): Path to where experiment is located.\n            trials (list|None): List of trials that can be accessed via\n                `analysis.trials`.\n        \"\"\"\n        with open(experiment_checkpoint_path) as f:\n            _experiment_state = json.load(f)\n            self._experiment_state = _experiment_state\n\n        if \"checkpoints\" not in _experiment_state:\n            raise TuneError(\"Experiment state invalid; no checkpoints found.\")\n        self._checkpoints = _experiment_state[\"checkpoints\"]\n        self.trials = trials\n        super(ExperimentAnalysis, self).__init__(\n            os.path.dirname(experiment_checkpoint_path))\n\n    def stats(self):\n        \"\"\"Returns a dictionary of the statistics of the experiment.\"\"\"\n        return self._experiment_state.get(\"stats\")\n\n    def runner_data(self):\n        \"\"\"Returns a dictionary of the TrialRunner data.\"\"\"\n        return self._experiment_state.get(\"runner_data\")\n\n    def _get_trial_paths(self):\n        \"\"\"Overwrites Analysis to only have trials of one experiment.\"\"\"\n        if self.trials:\n            _trial_paths = [t.logdir for t in self.trials]\n        else:\n            logger.warning(\"No `self.trials`. Drawing logdirs from checkpoint \"\n                           \"file. This may result in some information that is \"\n                           \"out of sync, as checkpointing is periodic.\")\n            _trial_paths = [\n                checkpoint[\"logdir\"] for checkpoint in self._checkpoints\n            ]\n        if not _trial_paths:\n            raise TuneError(\"No trials found.\")\n        return _trial_paths\n", "path": "python/ray/tune/analysis/experiment_analysis.py"}], "after_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport json\nimport logging\nimport os\n\ntry:\n    import pandas as pd\nexcept ImportError:\n    pd = None\n\nfrom ray.tune.error import TuneError\nfrom ray.tune.result import EXPR_PROGRESS_FILE, EXPR_PARAM_FILE, CONFIG_PREFIX\n\nlogger = logging.getLogger(__name__)\n\n\nclass Analysis(object):\n    \"\"\"Analyze all results from a directory of experiments.\"\"\"\n\n    def __init__(self, experiment_dir):\n        experiment_dir = os.path.expanduser(experiment_dir)\n        if not os.path.isdir(experiment_dir):\n            raise ValueError(\n                \"{} is not a valid directory.\".format(experiment_dir))\n        self._experiment_dir = experiment_dir\n        self._configs = {}\n        self._trial_dataframes = {}\n\n        if not pd:\n            logger.warning(\n                \"pandas not installed. Run `pip install pandas` for \"\n                \"Analysis utilities.\")\n        else:\n            self.fetch_trial_dataframes()\n\n    def dataframe(self, metric=None, mode=None):\n        \"\"\"Returns a pandas.DataFrame object constructed from the trials.\n\n        Args:\n            metric (str): Key for trial info to order on.\n                If None, uses last result.\n            mode (str): One of [min, max].\n\n        \"\"\"\n        rows = self._retrieve_rows(metric=metric, mode=mode)\n        all_configs = self.get_all_configs(prefix=True)\n        for path, config in all_configs.items():\n            if path in rows:\n                rows[path].update(config)\n                rows[path].update(logdir=path)\n        return pd.DataFrame(list(rows.values()))\n\n    def get_best_config(self, metric, mode=\"max\"):\n        \"\"\"Retrieve the best config corresponding to the trial.\n\n        Args:\n            metric (str): Key for trial info to order on.\n            mode (str): One of [min, max].\n\n        \"\"\"\n        rows = self._retrieve_rows(metric=metric, mode=mode)\n        all_configs = self.get_all_configs()\n        compare_op = max if mode == \"max\" else min\n        best_path = compare_op(rows, key=lambda k: rows[k][metric])\n        return all_configs[best_path]\n\n    def get_best_logdir(self, metric, mode=\"max\"):\n        \"\"\"Retrieve the logdir corresponding to the best trial.\n\n        Args:\n            metric (str): Key for trial info to order on.\n            mode (str): One of [min, max].\n\n        \"\"\"\n        df = self.dataframe(metric=metric, mode=mode)\n        if mode == \"max\":\n            return df.iloc[df[metric].idxmax()].logdir\n        elif mode == \"min\":\n            return df.iloc[df[metric].idxmin()].logdir\n\n    def fetch_trial_dataframes(self):\n        fail_count = 0\n        for path in self._get_trial_paths():\n            try:\n                self.trial_dataframes[path] = pd.read_csv(\n                    os.path.join(path, EXPR_PROGRESS_FILE))\n            except Exception:\n                fail_count += 1\n\n        if fail_count:\n            logger.debug(\n                \"Couldn't read results from {} paths\".format(fail_count))\n        return self.trial_dataframes\n\n    def get_all_configs(self, prefix=False):\n        \"\"\"Returns a list of all configurations.\n\n        Parameters:\n            prefix (bool): If True, flattens the config dict\n                and prepends `config/`.\n        \"\"\"\n        fail_count = 0\n        for path in self._get_trial_paths():\n            try:\n                with open(os.path.join(path, EXPR_PARAM_FILE)) as f:\n                    config = json.load(f)\n                    if prefix:\n                        for k in list(config):\n                            config[CONFIG_PREFIX + k] = config.pop(k)\n                    self._configs[path] = config\n            except Exception:\n                fail_count += 1\n\n        if fail_count:\n            logger.warning(\n                \"Couldn't read config from {} paths\".format(fail_count))\n        return self._configs\n\n    def _retrieve_rows(self, metric=None, mode=None):\n        assert mode is None or mode in [\"max\", \"min\"]\n        rows = {}\n        for path, df in self.trial_dataframes.items():\n            if mode == \"max\":\n                idx = df[metric].idxmax()\n            elif mode == \"min\":\n                idx = df[metric].idxmin()\n            else:\n                idx = -1\n            rows[path] = df.iloc[idx].to_dict()\n\n        return rows\n\n    def _get_trial_paths(self):\n        _trial_paths = []\n        for trial_path, _, files in os.walk(self._experiment_dir):\n            if EXPR_PROGRESS_FILE in files:\n                _trial_paths += [trial_path]\n\n        if not _trial_paths:\n            raise TuneError(\"No trials found in {}.\".format(\n                self._experiment_dir))\n        return _trial_paths\n\n    @property\n    def trial_dataframes(self):\n        \"\"\"List of all dataframes of the trials.\"\"\"\n        return self._trial_dataframes\n\n\nclass ExperimentAnalysis(Analysis):\n    \"\"\"Analyze results from a Tune experiment.\n\n    Parameters:\n        experiment_checkpoint_path (str): Path to a json file\n            representing an experiment state. Corresponds to\n            Experiment.local_dir/Experiment.name/experiment_state.json\n\n    Example:\n        >>> tune.run(my_trainable, name=\"my_exp\", local_dir=\"~/tune_results\")\n        >>> analysis = ExperimentAnalysis(\n        >>>     experiment_checkpoint_path=\"~/tune_results/my_exp/state.json\")\n    \"\"\"\n\n    def __init__(self, experiment_checkpoint_path, trials=None):\n        \"\"\"Initializer.\n\n        Args:\n            experiment_path (str): Path to where experiment is located.\n            trials (list|None): List of trials that can be accessed via\n                `analysis.trials`.\n        \"\"\"\n        with open(experiment_checkpoint_path) as f:\n            _experiment_state = json.load(f)\n            self._experiment_state = _experiment_state\n\n        if \"checkpoints\" not in _experiment_state:\n            raise TuneError(\"Experiment state invalid; no checkpoints found.\")\n        self._checkpoints = _experiment_state[\"checkpoints\"]\n        self.trials = trials\n        super(ExperimentAnalysis, self).__init__(\n            os.path.dirname(experiment_checkpoint_path))\n\n    def stats(self):\n        \"\"\"Returns a dictionary of the statistics of the experiment.\"\"\"\n        return self._experiment_state.get(\"stats\")\n\n    def runner_data(self):\n        \"\"\"Returns a dictionary of the TrialRunner data.\"\"\"\n        return self._experiment_state.get(\"runner_data\")\n\n    def _get_trial_paths(self):\n        \"\"\"Overwrites Analysis to only have trials of one experiment.\"\"\"\n        if self.trials:\n            _trial_paths = [t.logdir for t in self.trials]\n        else:\n            logger.warning(\"No `self.trials`. Drawing logdirs from checkpoint \"\n                           \"file. This may result in some information that is \"\n                           \"out of sync, as checkpointing is periodic.\")\n            _trial_paths = [\n                checkpoint[\"logdir\"] for checkpoint in self._checkpoints\n            ]\n        if not _trial_paths:\n            raise TuneError(\"No trials found.\")\n        return _trial_paths\n", "path": "python/ray/tune/analysis/experiment_analysis.py"}]}