From: Steven Robertson <srtrumpetaggie@gmail.com>
Date: Sun, 7 Feb 2021 13:09:17 -0800
Subject: check Ansible version before loaders are loaded

Origin: upstream, https://github.com/mitogen-hq/mitogen/commit/234dde5fc1394d4ac6f855426e7794c97cc53f91
---
 ansible_mitogen/loaders.py  | 67 +++++++++++++++++++++++++++++++++++----------
 ansible_mitogen/planner.py  | 10 -------
 ansible_mitogen/strategy.py | 48 +-------------------------------
 3 files changed, 54 insertions(+), 71 deletions(-)

diff --git a/ansible_mitogen/loaders.py b/ansible_mitogen/loaders.py
index 00a89b7..c00915d 100644
--- a/ansible_mitogen/loaders.py
+++ b/ansible_mitogen/loaders.py
@@ -31,6 +31,7 @@ Stable names for PluginLoader instances across Ansible versions.
 """
 
 from __future__ import absolute_import
+import distutils.version
 
 __all__ = [
     'action_loader',
@@ -41,21 +42,59 @@ __all__ = [
     'strategy_loader',
 ]
 
-try:
-    from ansible.plugins.loader import action_loader
-    from ansible.plugins.loader import connection_loader
-    from ansible.plugins.loader import module_loader
-    from ansible.plugins.loader import module_utils_loader
-    from ansible.plugins.loader import shell_loader
-    from ansible.plugins.loader import strategy_loader
-except ImportError:  # Ansible <2.4
-    from ansible.plugins import action_loader
-    from ansible.plugins import connection_loader
-    from ansible.plugins import module_loader
-    from ansible.plugins import module_utils_loader
-    from ansible.plugins import shell_loader
-    from ansible.plugins import strategy_loader
+import ansible
 
+ANSIBLE_VERSION_MIN = (2, 10)
+ANSIBLE_VERSION_MAX = (2, 10)
+
+NEW_VERSION_MSG = (
+    "Your Ansible version (%s) is too recent. The most recent version\n"
+    "supported by Mitogen for Ansible is %s.x. Please check the Mitogen\n"
+    "release notes to see if a new version is available, otherwise\n"
+    "subscribe to the corresponding GitHub issue to be notified when\n"
+    "support becomes available.\n"
+    "\n"
+    "    https://mitogen.rtfd.io/en/latest/changelog.html\n"
+    "    https://github.com/mitogen-hq/mitogen/issues/\n"
+)
+OLD_VERSION_MSG = (
+    "Your version of Ansible (%s) is too old. The oldest version supported by "
+    "Mitogen for Ansible is %s."
+)
+
+
+def assert_supported_release():
+    """
+    Throw AnsibleError with a descriptive message in case of being loaded into
+    an unsupported Ansible release.
+    """
+    v = ansible.__version__
+    if not isinstance(v, tuple):
+        v = tuple(distutils.version.LooseVersion(v).version)
+
+    if v[:2] < ANSIBLE_VERSION_MIN:
+        raise ansible.errors.AnsibleError(
+            OLD_VERSION_MSG % (v, ANSIBLE_VERSION_MIN)
+        )
+
+    if v[:2] > ANSIBLE_VERSION_MAX:
+        raise ansible.errors.AnsibleError(
+            NEW_VERSION_MSG % (ansible.__version__, ANSIBLE_VERSION_MAX)
+        )
+
+
+# this is the first file our strategy plugins import, so we need to check this here
+# in prior Ansible versions, connection_loader.get_with_context didn't exist, so if a user
+# is trying to load an old Ansible version, we'll fail and error gracefully
+assert_supported_release()
+
+
+from ansible.plugins.loader import action_loader
+from ansible.plugins.loader import connection_loader
+from ansible.plugins.loader import module_loader
+from ansible.plugins.loader import module_utils_loader
+from ansible.plugins.loader import shell_loader
+from ansible.plugins.loader import strategy_loader
 
 # These are original, unwrapped implementations
 action_loader__get = action_loader.get
diff --git a/ansible_mitogen/planner.py b/ansible_mitogen/planner.py
index faf8d19..c0913a3 100644
--- a/ansible_mitogen/planner.py
+++ b/ansible_mitogen/planner.py
@@ -436,26 +436,16 @@ def py_modname_from_path(name, path):
     Fetch the logical name of a new-style module as it might appear in
     :data:`sys.modules` of the target's Python interpreter.
 
-    * For Ansible <2.7, this is an unpackaged module named like
-      "ansible_module_%s".
-
-    * For Ansible <2.9, this is an unpackaged module named like
-      "ansible.modules.%s"
-
     * Since Ansible 2.9, modules appearing within a package have the original
       package hierarchy approximated on the target, enabling relative imports
       to function correctly. For example, "ansible.modules.system.setup".
     """
-    # 2.9+
     if _get_ansible_module_fqn:
         try:
             return _get_ansible_module_fqn(path)
         except ValueError:
             pass
 
-    if ansible.__version__ < '2.7':
-        return 'ansible_module_' + name
-
     return 'ansible.modules.' + name
 
 
diff --git a/ansible_mitogen/strategy.py b/ansible_mitogen/strategy.py
index ddc0a5b..792cfad 100644
--- a/ansible_mitogen/strategy.py
+++ b/ansible_mitogen/strategy.py
@@ -27,7 +27,6 @@
 # POSSIBILITY OF SUCH DAMAGE.
 
 from __future__ import absolute_import
-import distutils.version
 import os
 import signal
 import threading
@@ -43,52 +42,8 @@ import ansible_mitogen.loaders
 import ansible_mitogen.mixins
 import ansible_mitogen.process
 
-import ansible
 import ansible.executor.process.worker
-
-try:
-    # 2.8+ has a standardized "unset" object.
-    from ansible.utils.sentinel import Sentinel
-except ImportError:
-    Sentinel = None
-
-ANSIBLE_VERSION_MIN = (2, 10)
-ANSIBLE_VERSION_MAX = (2, 10)
-
-NEW_VERSION_MSG = (
-    "Your Ansible version (%s) is too recent. The most recent version\n"
-    "supported by Mitogen for Ansible is %s.x. Please check the Mitogen\n"
-    "release notes to see if a new version is available, otherwise\n"
-    "subscribe to the corresponding GitHub issue to be notified when\n"
-    "support becomes available.\n"
-    "\n"
-    "    https://mitogen.rtfd.io/en/latest/changelog.html\n"
-    "    https://github.com/dw/mitogen/issues/\n"
-)
-OLD_VERSION_MSG = (
-    "Your version of Ansible (%s) is too old. The oldest version supported by "
-    "Mitogen for Ansible is %s."
-)
-
-
-def _assert_supported_release():
-    """
-    Throw AnsibleError with a descriptive message in case of being loaded into
-    an unsupported Ansible release.
-    """
-    v = ansible.__version__
-    if not isinstance(v, tuple):
-        v = tuple(distutils.version.LooseVersion(v).version)
-
-    if v[:2] < ANSIBLE_VERSION_MIN:
-        raise ansible.errors.AnsibleError(
-            OLD_VERSION_MSG % (v, ANSIBLE_VERSION_MIN)
-        )
-
-    if v[:2] > ANSIBLE_VERSION_MAX:
-        raise ansible.errors.AnsibleError(
-            NEW_VERSION_MSG % (ansible.__version__, ANSIBLE_VERSION_MAX)
-        )
+from ansible.utils.sentinel import Sentinel
 
 
 def _patch_awx_callback():
@@ -351,7 +306,6 @@ class StrategyMixin(object):
         Wrap :meth:`run` to ensure requisite infrastructure and modifications
         are configured for the duration of the call.
         """
-        _assert_supported_release()
         wrappers = AnsibleWrappers()
         self._worker_model = self._get_worker_model()
         ansible_mitogen.process.set_worker_model(self._worker_model)
