Support using importlib on py>=3 to avoid imp deprecation (#54883)

* Support using importlib on py>=3 to avoid imp deprecation

* Add changelog fragment

* importlib coverage for py3

* Ansiballz execute should use importlib too

* recursive module_utils finder should utilize importlib too

* don't be dumb

* Fix up units

* Clean up tests

* Prefer importlib.util in plugin loader when available

* insert the module into sys.modules

* 3 before 2 for consistency

* ci_complete

* Address importlib.util.find_spec returning None
This commit is contained in:
Matt Martz 2019-04-25 10:28:18 -05:00 committed by GitHub
parent 6d645c127f
commit 2732cde031
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 120 additions and 63 deletions

View file

@ -19,23 +19,18 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import imp
import pytest
import zipfile
from collections import namedtuple
from functools import partial
from io import BytesIO, StringIO
from io import BytesIO
import ansible.errors
from ansible.executor.module_common import recursive_finder
from ansible.module_utils.six import PY2
from ansible.module_utils.six.moves import builtins
original_find_module = imp.find_module
# These are the modules that are brought in by module_utils/basic.py This may need to be updated
# when basic.py gains new imports
# We will remove these when we modify AnsiBallZ to store its args in a separate file instead of in
@ -108,18 +103,6 @@ def finder_containers():
return FinderContainers(py_module_names, py_module_cache, zf)
def find_module_foo(module_utils_data, *args, **kwargs):
if args[0] == 'foo':
return (module_utils_data, '/usr/lib/python2.7/site-packages/ansible/module_utils/foo.py', ('.py', 'r', imp.PY_SOURCE))
return original_find_module(*args, **kwargs)
def find_package_foo(module_utils_data, *args, **kwargs):
if args[0] == 'foo':
return (module_utils_data, '/usr/lib/python2.7/site-packages/ansible/module_utils/foo', ('', '', imp.PKG_DIRECTORY))
return original_find_module(*args, **kwargs)
class TestRecursiveFinder(object):
def test_no_module_utils(self, finder_containers):
name = 'ping'
@ -145,11 +128,15 @@ class TestRecursiveFinder(object):
def test_from_import_toplevel_package(self, finder_containers, mocker):
if PY2:
module_utils_data = BytesIO(b'# License\ndef do_something():\n pass\n')
module_utils_data = b'# License\ndef do_something():\n pass\n'
else:
module_utils_data = StringIO(u'# License\ndef do_something():\n pass\n')
mocker.patch('imp.find_module', side_effect=partial(find_package_foo, module_utils_data))
mocker.patch('ansible.executor.module_common._slurp', side_effect=lambda x: b'# License\ndef do_something():\n pass\n')
module_utils_data = u'# License\ndef do_something():\n pass\n'
mi_mock = mocker.patch('ansible.executor.module_common.ModuleInfo')
mi_inst = mi_mock()
mi_inst.pkg_dir = True
mi_inst.py_src = False
mi_inst.path = '/path/to/ansible/module_utils/foo/__init__.py'
mi_inst.get_source.return_value = module_utils_data
name = 'ping'
data = b'#!/usr/bin/python\nfrom ansible.module_utils import foo'
@ -161,20 +148,22 @@ class TestRecursiveFinder(object):
assert frozenset(finder_containers.zf.namelist()) == frozenset(('ansible/module_utils/foo/__init__.py',)).union(ONLY_BASIC_FILE)
def test_from_import_toplevel_module(self, finder_containers, mocker):
if PY2:
module_utils_data = BytesIO(b'# License\ndef do_something():\n pass\n')
else:
module_utils_data = StringIO(u'# License\ndef do_something():\n pass\n')
mocker.patch('imp.find_module', side_effect=partial(find_module_foo, module_utils_data))
module_utils_data = b'# License\ndef do_something():\n pass\n'
mi_mock = mocker.patch('ansible.executor.module_common.ModuleInfo')
mi_inst = mi_mock()
mi_inst.pkg_dir = False
mi_inst.py_src = True
mi_inst.path = '/path/to/ansible/module_utils/foo.py'
mi_inst.get_source.return_value = module_utils_data
name = 'ping'
data = b'#!/usr/bin/python\nfrom ansible.module_utils import foo'
recursive_finder(name, data, *finder_containers)
mocker.stopall()
assert finder_containers.py_module_names == set((('foo',),)).union(MODULE_UTILS_BASIC_IMPORTS)
assert finder_containers.py_module_names == set((('foo',),)).union(ONLY_BASIC_IMPORT)
assert finder_containers.py_module_cache == {}
assert frozenset(finder_containers.zf.namelist()) == frozenset(('ansible/module_utils/foo.py',)).union(MODULE_UTILS_BASIC_FILES)
assert frozenset(finder_containers.zf.namelist()) == frozenset(('ansible/module_utils/foo.py',)).union(ONLY_BASIC_FILE)
#
# Test importing six with many permutations because it is not a normal module