We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add a flag to list all Upgrade Check Rules
It would be nice to have a list of all the available uprade-checks rules:

```
❯ airflow upgrade_check --help
usage: airflow upgrade_check [-h] [-s SAVE] [-i IGNORE] [-c CONFIG]

optional arguments:
  -h, --help            show this help message and exit
  -s SAVE, --save SAVE  Saves the result to the indicated file. The file
                        format is determined by the file extension.
  -i IGNORE, --ignore IGNORE
                        Ignore a rule. Can be used multiple times.
  -c CONFIG, --config CONFIG
                        Path to upgrade check config yaml file.
```

example (Ideally it should have 2 columns: Check_ID / Class Name and Summary):

```
❯ airflow upgrade_check --list

- Check for latest versions of apache-airflow and checker
- Remove airflowAirflowMacroPlugin class
- Chain between DAG and operator not allowed
- Connectionconn_id is not unique
- Connectionconn_type is not nullable
- Ensure users are not using custom metaclasses in custom operators
- Fernet is enabled by default
- GCP service account key deprecation
- Unify hostname_callable option in core section
- Changes in import paths of hooks, operators, sensors and others
- Users must delete deprecated configs for KubernetesExecutor
- Legacy UI is deprecated by default
- Logging configuration has been moved to new section
- Removal of Mesos Executor
- No additional argument allowed in BaseOperator
- Users must set a kubernetespod_template_file value
- SendGrid email uses old airflowcontrib module
- Changes in import path of remote task handlers
- Jinja Template Variables cannot be undefined
```

Related Slack conversation: https://apache-airflow.slack.com/archives/CCQB40SQJ/p1609259241092000

This allows users to know the progress of their checks and an easy way to ignore a check beforehand (if we list an id / class name too, example `PodTemplateFileRule`).

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `airflow/upgrade/checker.py`
Content:
```
1 # Licensed to the Apache Software Foundation (ASF) under one
2 # or more contributor license agreements.  See the NOTICE file
3 # distributed with this work for additional information
4 # regarding copyright ownership.  The ASF licenses this file
5 # to you under the Apache License, Version 2.0 (the
6 # "License"); you may not use this file except in compliance
7 # with the License.  You may obtain a copy of the License at
8 #
9 #   http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing,
12 # software distributed under the License is distributed on an
13 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 # KIND, either express or implied.  See the License for the
15 # specific language governing permissions and limitations
16 # under the License.
17 
18 from __future__ import absolute_import
19 import argparse
20 import logging
21 import sys
22 from typing import List
23 
24 from airflow.upgrade.formatters import BaseFormatter
25 from airflow.upgrade.problem import RuleStatus
26 from airflow.upgrade.rules import get_rules
27 from airflow.upgrade.rules.base_rule import BaseRule
28 
29 ALL_RULES = [cls() for cls in get_rules()]  # type: List[BaseRule]
30 
31 
32 def check_upgrade(formatter, rules):
33     # type: (BaseFormatter, List[BaseRule]) -> List[RuleStatus]
34     formatter.start_checking(rules)
35     all_rule_statuses = []  # List[RuleStatus]
36     for rule in rules:
37         rule_status = RuleStatus.from_rule(rule)
38         all_rule_statuses.append(rule_status)
39         formatter.on_next_rule_status(rule_status)
40     formatter.end_checking(all_rule_statuses)
41     return all_rule_statuses
42 
43 
44 def register_arguments(subparser):
45     subparser.add_argument(
46         "-s", "--save",
47         help="Saves the result to the indicated file. The file format is determined by the file extension."
48     )
49     subparser.add_argument(
50         "-i", "--ignore",
51         help="Ignore a rule. Can be used multiple times.",
52         action='append',
53     )
54     subparser.add_argument(
55         "-c", "--config",
56         help="Path to upgrade check config yaml file.",
57     )
58     subparser.set_defaults(func=run)
59 
60 
61 def run(args):
62     from airflow.upgrade.formatters import (ConsoleFormatter, JSONFormatter)
63     from airflow.upgrade.config import UpgradeConfig
64 
65     if args.save:
66         filename = args.save
67         if not filename.lower().endswith(".json"):
68             exit("Only JSON files are supported")
69         formatter = JSONFormatter(args.save)
70     else:
71         formatter = ConsoleFormatter()
72 
73     rules = ALL_RULES
74     ignored_rules = args.ignore or []
75 
76     if args.config:
77         print("Using config file:", args.config)
78         upgrade_config = UpgradeConfig.read(path=args.config)
79         rules.extend(upgrade_config.get_custom_rules())
80         ignored_rules.extend(upgrade_config.get_ignored_rules())
81 
82     rules = [r for r in rules if r.__class__.__name__ not in ignored_rules]
83 
84     # Disable ERROR and below logs to avoid them in console output.
85     # We want to show only output of upgrade_check command
86     logging.disable(logging.ERROR)
87 
88     all_problems = check_upgrade(formatter, rules)
89     if all_problems:
90         sys.exit(1)
91 
92 
93 def __main__():
94     parser = argparse.ArgumentParser()
95     register_arguments(parser)
96     args = parser.parse_args()
97     args.func(args)
98 
99 
100 if __name__ == "__main__":
101     __main__()
102
```

Path: `airflow/upgrade/rules/__init__.py`
Content:
```
1 # Licensed to the Apache Software Foundation (ASF) under one
2 # or more contributor license agreements.  See the NOTICE file
3 # distributed with this work for additional information
4 # regarding copyright ownership.  The ASF licenses this file
5 # to you under the Apache License, Version 2.0 (the
6 # "License"); you may not use this file except in compliance
7 # with the License.  You may obtain a copy of the License at
8 #
9 #   http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing,
12 # software distributed under the License is distributed on an
13 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 # KIND, either express or implied.  See the License for the
15 # specific language governing permissions and limitations
16 # under the License.
17 import os
18 
19 
20 def get_rules():
21     """Automatically discover all rules"""
22     rule_classes = []
23     path = os.path.dirname(os.path.abspath(__file__))
24     for file in sorted(os.listdir(path)):
25         if not file.endswith(".py") or file in ("__init__.py", "base_rule.py"):
26             continue
27         py_file = file[:-3]
28         mod = __import__(".".join([__name__, py_file]), fromlist=[py_file])
29         classes = [getattr(mod, x) for x in dir(mod) if isinstance(getattr(mod, x), type)]
30         for cls in classes:
31             bases = [b.__name__ for b in cls.__bases__]
32             if cls.__name__ != "BaseRule" and "BaseRule" in bases:
33                 rule_classes.append(cls)
34     return rule_classes
35
```
--- 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/airflow/upgrade/checker.py b/airflow/upgrade/checker.py
--- a/airflow/upgrade/checker.py
+++ b/airflow/upgrade/checker.py
@@ -41,6 +41,15 @@
     return all_rule_statuses
 
 
+def list_checks():
+    print()
+    print("Upgrade Checks:")
+    for rule in ALL_RULES:
+        rule_name = rule.__class__.__name__
+        print("- {}: {}".format(rule_name, rule.title))
+    print()
+
+
 def register_arguments(subparser):
     subparser.add_argument(
         "-s", "--save",
@@ -49,17 +58,21 @@
     subparser.add_argument(
         "-i", "--ignore",
         help="Ignore a rule. Can be used multiple times.",
-        action='append',
+        action="append",
     )
     subparser.add_argument(
         "-c", "--config",
         help="Path to upgrade check config yaml file.",
     )
-    subparser.set_defaults(func=run)
+    subparser.add_argument(
+        "-l", "--list",
+        help="List the upgrade checks and their class names",
+        action="store_true",
+    )
 
 
 def run(args):
-    from airflow.upgrade.formatters import (ConsoleFormatter, JSONFormatter)
+    from airflow.upgrade.formatters import ConsoleFormatter, JSONFormatter
     from airflow.upgrade.config import UpgradeConfig
 
     if args.save:
@@ -94,7 +107,10 @@
     parser = argparse.ArgumentParser()
     register_arguments(parser)
     args = parser.parse_args()
-    args.func(args)
+    if args.list:
+        list_checks()
+    else:
+        run(args)
 
 
 if __name__ == "__main__":
diff --git a/airflow/upgrade/rules/__init__.py b/airflow/upgrade/rules/__init__.py
--- a/airflow/upgrade/rules/__init__.py
+++ b/airflow/upgrade/rules/__init__.py
@@ -31,4 +31,6 @@
             bases = [b.__name__ for b in cls.__bases__]
             if cls.__name__ != "BaseRule" and "BaseRule" in bases:
                 rule_classes.append(cls)
-    return rule_classes
+    # Sort rules alphabetically by class name, while maintaining that the airflow version
+    # check should remain first
+    return rule_classes[:1] + sorted(rule_classes[1:], key=lambda r: r.__name__)

{"golden_diff": "diff --git a/airflow/upgrade/checker.py b/airflow/upgrade/checker.py\n--- a/airflow/upgrade/checker.py\n+++ b/airflow/upgrade/checker.py\n@@ -41,6 +41,15 @@\n     return all_rule_statuses\n \n \n+def list_checks():\n+    print()\n+    print(\"Upgrade Checks:\")\n+    for rule in ALL_RULES:\n+        rule_name = rule.__class__.__name__\n+        print(\"- {}: {}\".format(rule_name, rule.title))\n+    print()\n+\n+\n def register_arguments(subparser):\n     subparser.add_argument(\n         \"-s\", \"--save\",\n@@ -49,17 +58,21 @@\n     subparser.add_argument(\n         \"-i\", \"--ignore\",\n         help=\"Ignore a rule. Can be used multiple times.\",\n-        action='append',\n+        action=\"append\",\n     )\n     subparser.add_argument(\n         \"-c\", \"--config\",\n         help=\"Path to upgrade check config yaml file.\",\n     )\n-    subparser.set_defaults(func=run)\n+    subparser.add_argument(\n+        \"-l\", \"--list\",\n+        help=\"List the upgrade checks and their class names\",\n+        action=\"store_true\",\n+    )\n \n \n def run(args):\n-    from airflow.upgrade.formatters import (ConsoleFormatter, JSONFormatter)\n+    from airflow.upgrade.formatters import ConsoleFormatter, JSONFormatter\n     from airflow.upgrade.config import UpgradeConfig\n \n     if args.save:\n@@ -94,7 +107,10 @@\n     parser = argparse.ArgumentParser()\n     register_arguments(parser)\n     args = parser.parse_args()\n-    args.func(args)\n+    if args.list:\n+        list_checks()\n+    else:\n+        run(args)\n \n \n if __name__ == \"__main__\":\ndiff --git a/airflow/upgrade/rules/__init__.py b/airflow/upgrade/rules/__init__.py\n--- a/airflow/upgrade/rules/__init__.py\n+++ b/airflow/upgrade/rules/__init__.py\n@@ -31,4 +31,6 @@\n             bases = [b.__name__ for b in cls.__bases__]\n             if cls.__name__ != \"BaseRule\" and \"BaseRule\" in bases:\n                 rule_classes.append(cls)\n-    return rule_classes\n+    # Sort rules alphabetically by class name, while maintaining that the airflow version\n+    # check should remain first\n+    return rule_classes[:1] + sorted(rule_classes[1:], key=lambda r: r.__name__)\n", "issue": "Add a flag to list all Upgrade Check Rules\nIt would be nice to have a list of all the available uprade-checks rules:\r\n\r\n```\r\n\u276f airflow upgrade_check --help\r\nusage: airflow upgrade_check [-h] [-s SAVE] [-i IGNORE] [-c CONFIG]\r\n\r\noptional arguments:\r\n  -h, --help            show this help message and exit\r\n  -s SAVE, --save SAVE  Saves the result to the indicated file. The file\r\n                        format is determined by the file extension.\r\n  -i IGNORE, --ignore IGNORE\r\n                        Ignore a rule. Can be used multiple times.\r\n  -c CONFIG, --config CONFIG\r\n                        Path to upgrade check config yaml file.\r\n```\r\n\r\nexample (Ideally it should have 2 columns: Check_ID / Class Name and Summary):\r\n\r\n```\r\n\u276f airflow upgrade_check --list\r\n\r\n- Check for latest versions of apache-airflow and checker\r\n- Remove airflowAirflowMacroPlugin class\r\n- Chain between DAG and operator not allowed\r\n- Connectionconn_id is not unique\r\n- Connectionconn_type is not nullable\r\n- Ensure users are not using custom metaclasses in custom operators\r\n- Fernet is enabled by default\r\n- GCP service account key deprecation\r\n- Unify hostname_callable option in core section\r\n- Changes in import paths of hooks, operators, sensors and others\r\n- Users must delete deprecated configs for KubernetesExecutor\r\n- Legacy UI is deprecated by default\r\n- Logging configuration has been moved to new section\r\n- Removal of Mesos Executor\r\n- No additional argument allowed in BaseOperator\r\n- Users must set a kubernetespod_template_file value\r\n- SendGrid email uses old airflowcontrib module\r\n- Changes in import path of remote task handlers\r\n- Jinja Template Variables cannot be undefined\r\n```\r\n\r\nRelated Slack conversation: https://apache-airflow.slack.com/archives/CCQB40SQJ/p1609259241092000\r\n\r\nThis allows users to know the progress of their checks and an easy way to ignore a check beforehand (if we list an id / class name too, example `PodTemplateFileRule`).\n", "before_files": [{"content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n\nfrom __future__ import absolute_import\nimport argparse\nimport logging\nimport sys\nfrom typing import List\n\nfrom airflow.upgrade.formatters import BaseFormatter\nfrom airflow.upgrade.problem import RuleStatus\nfrom airflow.upgrade.rules import get_rules\nfrom airflow.upgrade.rules.base_rule import BaseRule\n\nALL_RULES = [cls() for cls in get_rules()]  # type: List[BaseRule]\n\n\ndef check_upgrade(formatter, rules):\n    # type: (BaseFormatter, List[BaseRule]) -> List[RuleStatus]\n    formatter.start_checking(rules)\n    all_rule_statuses = []  # List[RuleStatus]\n    for rule in rules:\n        rule_status = RuleStatus.from_rule(rule)\n        all_rule_statuses.append(rule_status)\n        formatter.on_next_rule_status(rule_status)\n    formatter.end_checking(all_rule_statuses)\n    return all_rule_statuses\n\n\ndef register_arguments(subparser):\n    subparser.add_argument(\n        \"-s\", \"--save\",\n        help=\"Saves the result to the indicated file. The file format is determined by the file extension.\"\n    )\n    subparser.add_argument(\n        \"-i\", \"--ignore\",\n        help=\"Ignore a rule. Can be used multiple times.\",\n        action='append',\n    )\n    subparser.add_argument(\n        \"-c\", \"--config\",\n        help=\"Path to upgrade check config yaml file.\",\n    )\n    subparser.set_defaults(func=run)\n\n\ndef run(args):\n    from airflow.upgrade.formatters import (ConsoleFormatter, JSONFormatter)\n    from airflow.upgrade.config import UpgradeConfig\n\n    if args.save:\n        filename = args.save\n        if not filename.lower().endswith(\".json\"):\n            exit(\"Only JSON files are supported\")\n        formatter = JSONFormatter(args.save)\n    else:\n        formatter = ConsoleFormatter()\n\n    rules = ALL_RULES\n    ignored_rules = args.ignore or []\n\n    if args.config:\n        print(\"Using config file:\", args.config)\n        upgrade_config = UpgradeConfig.read(path=args.config)\n        rules.extend(upgrade_config.get_custom_rules())\n        ignored_rules.extend(upgrade_config.get_ignored_rules())\n\n    rules = [r for r in rules if r.__class__.__name__ not in ignored_rules]\n\n    # Disable ERROR and below logs to avoid them in console output.\n    # We want to show only output of upgrade_check command\n    logging.disable(logging.ERROR)\n\n    all_problems = check_upgrade(formatter, rules)\n    if all_problems:\n        sys.exit(1)\n\n\ndef __main__():\n    parser = argparse.ArgumentParser()\n    register_arguments(parser)\n    args = parser.parse_args()\n    args.func(args)\n\n\nif __name__ == \"__main__\":\n    __main__()\n", "path": "airflow/upgrade/checker.py"}, {"content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\nimport os\n\n\ndef get_rules():\n    \"\"\"Automatically discover all rules\"\"\"\n    rule_classes = []\n    path = os.path.dirname(os.path.abspath(__file__))\n    for file in sorted(os.listdir(path)):\n        if not file.endswith(\".py\") or file in (\"__init__.py\", \"base_rule.py\"):\n            continue\n        py_file = file[:-3]\n        mod = __import__(\".\".join([__name__, py_file]), fromlist=[py_file])\n        classes = [getattr(mod, x) for x in dir(mod) if isinstance(getattr(mod, x), type)]\n        for cls in classes:\n            bases = [b.__name__ for b in cls.__bases__]\n            if cls.__name__ != \"BaseRule\" and \"BaseRule\" in bases:\n                rule_classes.append(cls)\n    return rule_classes\n", "path": "airflow/upgrade/rules/__init__.py"}], "after_files": [{"content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n\nfrom __future__ import absolute_import\nimport argparse\nimport logging\nimport sys\nfrom typing import List\n\nfrom airflow.upgrade.formatters import BaseFormatter\nfrom airflow.upgrade.problem import RuleStatus\nfrom airflow.upgrade.rules import get_rules\nfrom airflow.upgrade.rules.base_rule import BaseRule\n\nALL_RULES = [cls() for cls in get_rules()]  # type: List[BaseRule]\n\n\ndef check_upgrade(formatter, rules):\n    # type: (BaseFormatter, List[BaseRule]) -> List[RuleStatus]\n    formatter.start_checking(rules)\n    all_rule_statuses = []  # List[RuleStatus]\n    for rule in rules:\n        rule_status = RuleStatus.from_rule(rule)\n        all_rule_statuses.append(rule_status)\n        formatter.on_next_rule_status(rule_status)\n    formatter.end_checking(all_rule_statuses)\n    return all_rule_statuses\n\n\ndef list_checks():\n    print()\n    print(\"Upgrade Checks:\")\n    for rule in ALL_RULES:\n        rule_name = rule.__class__.__name__\n        print(\"- {}: {}\".format(rule_name, rule.title))\n    print()\n\n\ndef register_arguments(subparser):\n    subparser.add_argument(\n        \"-s\", \"--save\",\n        help=\"Saves the result to the indicated file. The file format is determined by the file extension.\"\n    )\n    subparser.add_argument(\n        \"-i\", \"--ignore\",\n        help=\"Ignore a rule. Can be used multiple times.\",\n        action=\"append\",\n    )\n    subparser.add_argument(\n        \"-c\", \"--config\",\n        help=\"Path to upgrade check config yaml file.\",\n    )\n    subparser.add_argument(\n        \"-l\", \"--list\",\n        help=\"List the upgrade checks and their class names\",\n        action=\"store_true\",\n    )\n\n\ndef run(args):\n    from airflow.upgrade.formatters import ConsoleFormatter, JSONFormatter\n    from airflow.upgrade.config import UpgradeConfig\n\n    if args.save:\n        filename = args.save\n        if not filename.lower().endswith(\".json\"):\n            exit(\"Only JSON files are supported\")\n        formatter = JSONFormatter(args.save)\n    else:\n        formatter = ConsoleFormatter()\n\n    rules = ALL_RULES\n    ignored_rules = args.ignore or []\n\n    if args.config:\n        print(\"Using config file:\", args.config)\n        upgrade_config = UpgradeConfig.read(path=args.config)\n        rules.extend(upgrade_config.get_custom_rules())\n        ignored_rules.extend(upgrade_config.get_ignored_rules())\n\n    rules = [r for r in rules if r.__class__.__name__ not in ignored_rules]\n\n    # Disable ERROR and below logs to avoid them in console output.\n    # We want to show only output of upgrade_check command\n    logging.disable(logging.ERROR)\n\n    all_problems = check_upgrade(formatter, rules)\n    if all_problems:\n        sys.exit(1)\n\n\ndef __main__():\n    parser = argparse.ArgumentParser()\n    register_arguments(parser)\n    args = parser.parse_args()\n    if args.list:\n        list_checks()\n    else:\n        run(args)\n\n\nif __name__ == \"__main__\":\n    __main__()\n", "path": "airflow/upgrade/checker.py"}, {"content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\nimport os\n\n\ndef get_rules():\n    \"\"\"Automatically discover all rules\"\"\"\n    rule_classes = []\n    path = os.path.dirname(os.path.abspath(__file__))\n    for file in sorted(os.listdir(path)):\n        if not file.endswith(\".py\") or file in (\"__init__.py\", \"base_rule.py\"):\n            continue\n        py_file = file[:-3]\n        mod = __import__(\".\".join([__name__, py_file]), fromlist=[py_file])\n        classes = [getattr(mod, x) for x in dir(mod) if isinstance(getattr(mod, x), type)]\n        for cls in classes:\n            bases = [b.__name__ for b in cls.__bases__]\n            if cls.__name__ != \"BaseRule\" and \"BaseRule\" in bases:\n                rule_classes.append(cls)\n    # Sort rules alphabetically by class name, while maintaining that the airflow version\n    # check should remain first\n    return rule_classes[:1] + sorted(rule_classes[1:], key=lambda r: r.__name__)\n", "path": "airflow/upgrade/rules/__init__.py"}]}