mirror of https://github.com/ansible/ansible.git
Update collection loader for Python 3.10 (#76225)
* Implement find_spec and exec_module to remove reliance on deprecated methods in the collection loader ci_complete * Move module execution to exec_module Remove extra sys.modules handling Use default module initialization by returning None from loader.create_module Refactor ci_complete * Remove ansible-test's copy of the collection loader ci_complete * Fix metaclass for Python 2.x ci_complete * Fix Py2/Py3 syntax compatibility * Refactor ci_complete * update collection_loader comments ci_complete * simplify find_module ci_complete * Fix Py2 compatibility - don't get loader from nonexistent spec Remove unnecessary PY3 checking * Refactor common code in load_module and exec_module ci_complete * tidy diff ci_complete * Include collection_loader in target paths for 'compile' sanity test * add changelog * Add "return None" instead of doing it implicitly Remove get_filename short-circuit exec_module if it's a redirect ci_completepull/76426/head
parent
1d1597ffd9
commit
b50f16db91
@ -0,0 +1,4 @@
|
||||
bugfixes:
|
||||
- >-
|
||||
collection_loader - Implement 'find_spec' and 'exec_module' to override deprecated importlib methods
|
||||
'find_module' and 'load_module' when applicable (https://github.com/ansible/ansible/issues/74660).
|
@ -1,31 +0,0 @@
|
||||
# (c) 2019 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# CAUTION: There are two implementations of the collection loader.
|
||||
# They must be kept functionally identical, although their implementations may differ.
|
||||
#
|
||||
# 1) The controller implementation resides in the "lib/ansible/utils/collection_loader/" directory.
|
||||
# It must function on all Python versions supported on the controller.
|
||||
# 2) The ansible-test implementation resides in the "test/lib/ansible_test/_util/target/legacy_collection_loader/" directory.
|
||||
# It must function on all Python versions supported on managed hosts which are not supported by the controller.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
# FIXME: decide what of this we want to actually be public/toplevel, put other stuff on a utility class?
|
||||
from ._collection_config import AnsibleCollectionConfig
|
||||
from ._collection_finder import AnsibleCollectionRef
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
|
||||
|
||||
def resource_from_fqcr(ref):
|
||||
"""
|
||||
Return resource from a fully-qualified collection reference,
|
||||
or from a simple resource name.
|
||||
For fully-qualified collection references, this is equivalent to
|
||||
``AnsibleCollectionRef.from_fqcr(ref).resource``.
|
||||
:param ref: collection reference to parse
|
||||
:return: the resource as a unicode string
|
||||
"""
|
||||
ref = to_text(ref, errors='strict')
|
||||
return ref.split(u'.')[-1]
|
@ -1,107 +0,0 @@
|
||||
# (c) 2019 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# CAUTION: There are two implementations of the collection loader.
|
||||
# They must be kept functionally identical, although their implementations may differ.
|
||||
#
|
||||
# 1) The controller implementation resides in the "lib/ansible/utils/collection_loader/" directory.
|
||||
# It must function on all Python versions supported on the controller.
|
||||
# 2) The ansible-test implementation resides in the "test/lib/ansible_test/_util/target/legacy_collection_loader/" directory.
|
||||
# It must function on all Python versions supported on managed hosts which are not supported by the controller.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.module_utils.six import with_metaclass
|
||||
|
||||
|
||||
class _EventSource:
|
||||
def __init__(self):
|
||||
self._handlers = set()
|
||||
|
||||
def __iadd__(self, handler):
|
||||
if not callable(handler):
|
||||
raise ValueError('handler must be callable')
|
||||
self._handlers.add(handler)
|
||||
return self
|
||||
|
||||
def __isub__(self, handler):
|
||||
try:
|
||||
self._handlers.remove(handler)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return self
|
||||
|
||||
def _on_exception(self, handler, exc, *args, **kwargs):
|
||||
# if we return True, we want the caller to re-raise
|
||||
return True
|
||||
|
||||
def fire(self, *args, **kwargs):
|
||||
for h in self._handlers:
|
||||
try:
|
||||
h(*args, **kwargs)
|
||||
except Exception as ex:
|
||||
if self._on_exception(h, ex, *args, **kwargs):
|
||||
raise
|
||||
|
||||
|
||||
class _AnsibleCollectionConfig(type):
|
||||
def __init__(cls, meta, name, bases):
|
||||
cls._collection_finder = None
|
||||
cls._default_collection = None
|
||||
cls._on_collection_load = _EventSource()
|
||||
|
||||
@property
|
||||
def collection_finder(cls):
|
||||
return cls._collection_finder
|
||||
|
||||
@collection_finder.setter
|
||||
def collection_finder(cls, value):
|
||||
if cls._collection_finder:
|
||||
raise ValueError('an AnsibleCollectionFinder has already been configured')
|
||||
|
||||
cls._collection_finder = value
|
||||
|
||||
@property
|
||||
def collection_paths(cls):
|
||||
cls._require_finder()
|
||||
return [to_text(p) for p in cls._collection_finder._n_collection_paths]
|
||||
|
||||
@property
|
||||
def default_collection(cls):
|
||||
return cls._default_collection
|
||||
|
||||
@default_collection.setter
|
||||
def default_collection(cls, value):
|
||||
|
||||
cls._default_collection = value
|
||||
|
||||
@property
|
||||
def on_collection_load(cls):
|
||||
return cls._on_collection_load
|
||||
|
||||
@on_collection_load.setter
|
||||
def on_collection_load(cls, value):
|
||||
if value is not cls._on_collection_load:
|
||||
raise ValueError('on_collection_load is not directly settable (use +=)')
|
||||
|
||||
@property
|
||||
def playbook_paths(cls):
|
||||
cls._require_finder()
|
||||
return [to_text(p) for p in cls._collection_finder._n_playbook_paths]
|
||||
|
||||
@playbook_paths.setter
|
||||
def playbook_paths(cls, value):
|
||||
cls._require_finder()
|
||||
cls._collection_finder.set_playbook_paths(value)
|
||||
|
||||
def _require_finder(cls):
|
||||
if not cls._collection_finder:
|
||||
raise NotImplementedError('an AnsibleCollectionFinder has not been installed in this process')
|
||||
|
||||
|
||||
# concrete class of our metaclass type that defines the class properties we want
|
||||
class AnsibleCollectionConfig(with_metaclass(_AnsibleCollectionConfig)):
|
||||
pass
|
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@
|
||||
# (c) 2019 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# CAUTION: There are two implementations of the collection loader.
|
||||
# They must be kept functionally identical, although their implementations may differ.
|
||||
#
|
||||
# 1) The controller implementation resides in the "lib/ansible/utils/collection_loader/" directory.
|
||||
# It must function on all Python versions supported on the controller.
|
||||
# 2) The ansible-test implementation resides in the "test/lib/ansible_test/_util/target/legacy_collection_loader/" directory.
|
||||
# It must function on all Python versions supported on managed hosts which are not supported by the controller.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
try:
|
||||
from collections.abc import Mapping # pylint: disable=ansible-bad-import-from
|
||||
except ImportError:
|
||||
from collections import Mapping # pylint: disable=ansible-bad-import-from,deprecated-class
|
||||
|
||||
from ansible.module_utils.common.yaml import yaml_load
|
||||
|
||||
|
||||
def _meta_yml_to_dict(yaml_string_data, content_id):
|
||||
"""
|
||||
Converts string YAML dictionary to a Python dictionary. This function may be monkeypatched to another implementation
|
||||
by some tools (eg the import sanity test).
|
||||
:param yaml_string_data: a bytes-ish YAML dictionary
|
||||
:param content_id: a unique ID representing the content to allow other implementations to cache the output
|
||||
:return: a Python dictionary representing the YAML dictionary content
|
||||
"""
|
||||
# NB: content_id is passed in, but not used by this implementation
|
||||
routing_dict = yaml_load(yaml_string_data)
|
||||
if not routing_dict:
|
||||
routing_dict = {}
|
||||
if not isinstance(routing_dict, Mapping):
|
||||
raise ValueError('collection metadata must be an instance of Python Mapping')
|
||||
return routing_dict
|
Loading…
Reference in New Issue