We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Handle NoneType comparison in _scores_to_ranks
```
TypeError: '<' not supported between instances of 'NoneType' and 'float'
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `app/grandchallenge/evaluation/utils.py`
Content:
```
1 from collections import OrderedDict
2 from typing import Tuple, NamedTuple, List, Callable, Iterable, Dict
3 
4 from grandchallenge.evaluation.models import Result
5 from grandchallenge.evaluation.templatetags.evaluation_extras import (
6     get_jsonpath
7 )
8 
9 
10 class Metric(NamedTuple):
11     path: str
12     reverse: bool
13 
14 
15 class Positions(NamedTuple):
16     ranks: Dict[str, float]
17     rank_scores: Dict[str, float]
18     rank_per_metric: Dict[str, Dict[str, float]]
19 
20 
21 def rank_results(
22     *,
23     results: Tuple[Result, ...],
24     metrics: Tuple[Metric, ...],
25     score_method: Callable,
26 ) -> Positions:
27     """
28     Calculates the overall rank for each result, along with the rank_score
29     and the rank per metric.
30     """
31 
32     results = _filter_valid_results(results=results, metrics=metrics)
33 
34     rank_per_metric = _get_rank_per_metric(results=results, metrics=metrics)
35 
36     rank_scores = {
37         pk: score_method([m for m in metrics.values()])
38         for pk, metrics in rank_per_metric.items()
39     }
40 
41     return Positions(
42         ranks=_scores_to_ranks(scores=rank_scores, reverse=False),
43         rank_scores=rank_scores,
44         rank_per_metric=rank_per_metric,
45     )
46 
47 
48 def _filter_valid_results(
49     *, results: Iterable[Result], metrics: Tuple[Metric, ...]
50 ) -> List[Result]:
51     """ Ensure that all of the metrics are in every result """
52     return [
53         res
54         for res in results
55         if all(get_jsonpath(res.metrics, m.path) != "" for m in metrics)
56     ]
57 
58 
59 def _get_rank_per_metric(
60     *, results: Iterable[Result], metrics: Tuple[Metric, ...]
61 ) -> Dict[str, Dict[str, float]]:
62     """
63     Takes results and calculates the rank for each of the individual metrics
64 
65     Returns a dictionary where the key is the pk of the result, and the
66     values is another dictionary where the key is the path of the metric and
67     the value is the rank of this result for this metric
68     """
69     metric_rank = {}
70     for metric in metrics:
71         # Extract the value of the metric for this primary key and sort on the
72         # value of the metric
73         metric_scores = {
74             res.pk: get_jsonpath(res.metrics, metric.path) for res in results
75         }
76         metric_rank[metric.path] = _scores_to_ranks(
77             scores=metric_scores, reverse=metric.reverse
78         )
79 
80     return {
81         res.pk: {
82             metric_path: ranks[res.pk]
83             for metric_path, ranks in metric_rank.items()
84         }
85         for res in results
86     }
87 
88 
89 def _scores_to_ranks(
90     *, scores: Dict, reverse: bool = False
91 ) -> Dict[str, float]:
92     """
93     Go from a score (a scalar) to a rank (integer). If two scalars are the
94     same then they will have the same rank.
95 
96     Takes a dictionary where the keys are the pk of the results and the values
97     are the scores.
98 
99     Outputs a dictionary where they keys are the pk of the results and the
100     values are the ranks.
101     """
102     scores = OrderedDict(
103         sorted(scores.items(), key=lambda t: t[1], reverse=reverse)
104     )
105 
106     ranks = {}
107     current_score = current_rank = None
108 
109     for idx, (pk, score) in enumerate(scores.items()):
110         if score != current_score:
111             current_score = score
112             current_rank = idx + 1
113 
114         ranks[pk] = current_rank
115 
116     return ranks
117
```
--- 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/app/grandchallenge/evaluation/utils.py b/app/grandchallenge/evaluation/utils.py
--- a/app/grandchallenge/evaluation/utils.py
+++ b/app/grandchallenge/evaluation/utils.py
@@ -52,7 +52,10 @@
     return [
         res
         for res in results
-        if all(get_jsonpath(res.metrics, m.path) != "" for m in metrics)
+        if all(
+            get_jsonpath(res.metrics, m.path) not in ["", None]
+            for m in metrics
+        )
     ]

{"golden_diff": "diff --git a/app/grandchallenge/evaluation/utils.py b/app/grandchallenge/evaluation/utils.py\n--- a/app/grandchallenge/evaluation/utils.py\n+++ b/app/grandchallenge/evaluation/utils.py\n@@ -52,7 +52,10 @@\n     return [\n         res\n         for res in results\n-        if all(get_jsonpath(res.metrics, m.path) != \"\" for m in metrics)\n+        if all(\n+            get_jsonpath(res.metrics, m.path) not in [\"\", None]\n+            for m in metrics\n+        )\n     ]\n", "issue": "Handle NoneType comparison in _scores_to_ranks\n```\r\nTypeError: '<' not supported between instances of 'NoneType' and 'float'\r\n```\n", "before_files": [{"content": "from collections import OrderedDict\nfrom typing import Tuple, NamedTuple, List, Callable, Iterable, Dict\n\nfrom grandchallenge.evaluation.models import Result\nfrom grandchallenge.evaluation.templatetags.evaluation_extras import (\n    get_jsonpath\n)\n\n\nclass Metric(NamedTuple):\n    path: str\n    reverse: bool\n\n\nclass Positions(NamedTuple):\n    ranks: Dict[str, float]\n    rank_scores: Dict[str, float]\n    rank_per_metric: Dict[str, Dict[str, float]]\n\n\ndef rank_results(\n    *,\n    results: Tuple[Result, ...],\n    metrics: Tuple[Metric, ...],\n    score_method: Callable,\n) -> Positions:\n    \"\"\"\n    Calculates the overall rank for each result, along with the rank_score\n    and the rank per metric.\n    \"\"\"\n\n    results = _filter_valid_results(results=results, metrics=metrics)\n\n    rank_per_metric = _get_rank_per_metric(results=results, metrics=metrics)\n\n    rank_scores = {\n        pk: score_method([m for m in metrics.values()])\n        for pk, metrics in rank_per_metric.items()\n    }\n\n    return Positions(\n        ranks=_scores_to_ranks(scores=rank_scores, reverse=False),\n        rank_scores=rank_scores,\n        rank_per_metric=rank_per_metric,\n    )\n\n\ndef _filter_valid_results(\n    *, results: Iterable[Result], metrics: Tuple[Metric, ...]\n) -> List[Result]:\n    \"\"\" Ensure that all of the metrics are in every result \"\"\"\n    return [\n        res\n        for res in results\n        if all(get_jsonpath(res.metrics, m.path) != \"\" for m in metrics)\n    ]\n\n\ndef _get_rank_per_metric(\n    *, results: Iterable[Result], metrics: Tuple[Metric, ...]\n) -> Dict[str, Dict[str, float]]:\n    \"\"\"\n    Takes results and calculates the rank for each of the individual metrics\n\n    Returns a dictionary where the key is the pk of the result, and the\n    values is another dictionary where the key is the path of the metric and\n    the value is the rank of this result for this metric\n    \"\"\"\n    metric_rank = {}\n    for metric in metrics:\n        # Extract the value of the metric for this primary key and sort on the\n        # value of the metric\n        metric_scores = {\n            res.pk: get_jsonpath(res.metrics, metric.path) for res in results\n        }\n        metric_rank[metric.path] = _scores_to_ranks(\n            scores=metric_scores, reverse=metric.reverse\n        )\n\n    return {\n        res.pk: {\n            metric_path: ranks[res.pk]\n            for metric_path, ranks in metric_rank.items()\n        }\n        for res in results\n    }\n\n\ndef _scores_to_ranks(\n    *, scores: Dict, reverse: bool = False\n) -> Dict[str, float]:\n    \"\"\"\n    Go from a score (a scalar) to a rank (integer). If two scalars are the\n    same then they will have the same rank.\n\n    Takes a dictionary where the keys are the pk of the results and the values\n    are the scores.\n\n    Outputs a dictionary where they keys are the pk of the results and the\n    values are the ranks.\n    \"\"\"\n    scores = OrderedDict(\n        sorted(scores.items(), key=lambda t: t[1], reverse=reverse)\n    )\n\n    ranks = {}\n    current_score = current_rank = None\n\n    for idx, (pk, score) in enumerate(scores.items()):\n        if score != current_score:\n            current_score = score\n            current_rank = idx + 1\n\n        ranks[pk] = current_rank\n\n    return ranks\n", "path": "app/grandchallenge/evaluation/utils.py"}], "after_files": [{"content": "from collections import OrderedDict\nfrom typing import Tuple, NamedTuple, List, Callable, Iterable, Dict\n\nfrom grandchallenge.evaluation.models import Result\nfrom grandchallenge.evaluation.templatetags.evaluation_extras import (\n    get_jsonpath\n)\n\n\nclass Metric(NamedTuple):\n    path: str\n    reverse: bool\n\n\nclass Positions(NamedTuple):\n    ranks: Dict[str, float]\n    rank_scores: Dict[str, float]\n    rank_per_metric: Dict[str, Dict[str, float]]\n\n\ndef rank_results(\n    *,\n    results: Tuple[Result, ...],\n    metrics: Tuple[Metric, ...],\n    score_method: Callable,\n) -> Positions:\n    \"\"\"\n    Calculates the overall rank for each result, along with the rank_score\n    and the rank per metric.\n    \"\"\"\n\n    results = _filter_valid_results(results=results, metrics=metrics)\n\n    rank_per_metric = _get_rank_per_metric(results=results, metrics=metrics)\n\n    rank_scores = {\n        pk: score_method([m for m in metrics.values()])\n        for pk, metrics in rank_per_metric.items()\n    }\n\n    return Positions(\n        ranks=_scores_to_ranks(scores=rank_scores, reverse=False),\n        rank_scores=rank_scores,\n        rank_per_metric=rank_per_metric,\n    )\n\n\ndef _filter_valid_results(\n    *, results: Iterable[Result], metrics: Tuple[Metric, ...]\n) -> List[Result]:\n    \"\"\" Ensure that all of the metrics are in every result \"\"\"\n    return [\n        res\n        for res in results\n        if all(\n            get_jsonpath(res.metrics, m.path) not in [\"\", None]\n            for m in metrics\n        )\n    ]\n\n\ndef _get_rank_per_metric(\n    *, results: Iterable[Result], metrics: Tuple[Metric, ...]\n) -> Dict[str, Dict[str, float]]:\n    \"\"\"\n    Takes results and calculates the rank for each of the individual metrics\n\n    Returns a dictionary where the key is the pk of the result, and the\n    values is another dictionary where the key is the path of the metric and\n    the value is the rank of this result for this metric\n    \"\"\"\n    metric_rank = {}\n    for metric in metrics:\n        # Extract the value of the metric for this primary key and sort on the\n        # value of the metric\n        metric_scores = {\n            res.pk: get_jsonpath(res.metrics, metric.path) for res in results\n        }\n        metric_rank[metric.path] = _scores_to_ranks(\n            scores=metric_scores, reverse=metric.reverse\n        )\n\n    return {\n        res.pk: {\n            metric_path: ranks[res.pk]\n            for metric_path, ranks in metric_rank.items()\n        }\n        for res in results\n    }\n\n\ndef _scores_to_ranks(\n    *, scores: Dict, reverse: bool = False\n) -> Dict[str, float]:\n    \"\"\"\n    Go from a score (a scalar) to a rank (integer). If two scalars are the\n    same then they will have the same rank.\n\n    Takes a dictionary where the keys are the pk of the results and the values\n    are the scores.\n\n    Outputs a dictionary where they keys are the pk of the results and the\n    values are the ranks.\n    \"\"\"\n    scores = OrderedDict(\n        sorted(scores.items(), key=lambda t: t[1], reverse=reverse)\n    )\n\n    ranks = {}\n    current_score = current_rank = None\n\n    for idx, (pk, score) in enumerate(scores.items()):\n        if score != current_score:\n            current_score = score\n            current_rank = idx + 1\n\n        ranks[pk] = current_rank\n\n    return ranks\n", "path": "app/grandchallenge/evaluation/utils.py"}]}