@@ -96,6 +96,9 @@ def __init__(self, action, connection, module_name, module_args,
9696 #: Initially ``None``, but set by :func:`invoke`. The raw source or
9797 #: binary contents of the module.
9898 self ._module_source = None
99+ #: Initially ``{}``, but set by :func:`invoke`. Optional source to send
100+ #: to :func:`propagate_paths_and_modules` to fix Python3.5 relative import errors
101+ self ._overridden_sources = {}
99102
100103 def get_module_source (self ):
101104 if self ._module_source is None :
@@ -476,6 +479,7 @@ def _propagate_deps(invocation, planner, context):
476479 context = context ,
477480 paths = planner .get_push_files (),
478481 modules = planner .get_module_deps (),
482+ overridden_sources = invocation ._overridden_sources
479483 )
480484
481485
@@ -533,6 +537,26 @@ def _get_planner(name, path, source):
533537 raise ansible .errors .AnsibleError (NO_METHOD_MSG + repr (invocation ))
534538
535539
540+ def _fix_py35 (invocation , module_source ):
541+ """
542+ super edge case with a relative import error in Python 3.5.1-3.5.3
543+ in Ansible's setup module when using Mitogen
544+ https://github.com/dw/mitogen/issues/672#issuecomment-636408833
545+ We replace a relative import in the setup module with the actual full file path
546+ This works in vanilla Ansible but not in Mitogen otherwise
547+ """
548+ if invocation .module_name == 'setup' and \
549+ invocation .module_path not in invocation ._overridden_sources :
550+ # in-memory replacement of setup module's relative import
551+ # would check for just python3.5 and run this then but we don't know the
552+ # target python at this time yet
553+ module_source = module_source .replace (
554+ b"from ...module_utils.basic import AnsibleModule" ,
555+ b"from ansible.module_utils.basic import AnsibleModule"
556+ )
557+ invocation ._overridden_sources [invocation .module_path ] = module_source
558+
559+
536560def invoke (invocation ):
537561 """
538562 Find a Planner subclass corresponding to `invocation` and use it to invoke
@@ -555,10 +579,12 @@ def invoke(invocation):
555579
556580 invocation .module_path = mitogen .core .to_text (path )
557581 if invocation .module_path not in _planner_by_path :
582+ module_source = invocation .get_module_source ()
583+ _fix_py35 (invocation , module_source )
558584 _planner_by_path [invocation .module_path ] = _get_planner (
559585 invocation .module_name ,
560586 invocation .module_path ,
561- invocation . get_module_source ()
587+ module_source
562588 )
563589
564590 planner = _planner_by_path [invocation .module_path ](invocation )
0 commit comments