From 108922a0736d6aef7129d217fe8302c0ec2a7d8d Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 27 Feb 2025 13:28:36 +1000 Subject: [PATCH] Fix up pkg logic --- .../collection-loader-extensions.yml | 1 - .../collection_loader/_collection_finder.py | 27 +++++++------------ 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/changelogs/fragments/collection-loader-extensions.yml b/changelogs/fragments/collection-loader-extensions.yml index 0d784a2af43..db523179f9e 100644 --- a/changelogs/fragments/collection-loader-extensions.yml +++ b/changelogs/fragments/collection-loader-extensions.yml @@ -3,4 +3,3 @@ bugfixes: collection loader - Fix the collection loader logic to correctly return Python module when calling ``pkgutil.iter_modules`` with a package that is inside a collection path and contains compiled Python extension modules. - diff --git a/lib/ansible/utils/collection_loader/_collection_finder.py b/lib/ansible/utils/collection_loader/_collection_finder.py index 753a4c80b12..9bc08960732 100644 --- a/lib/ansible/utils/collection_loader/_collection_finder.py +++ b/lib/ansible/utils/collection_loader/_collection_finder.py @@ -1238,7 +1238,8 @@ def _iter_modules_impl(paths, prefix=''): prefix = _to_text(prefix) # yield (module_loader, name, ispkg) for each module/pkg under path # TODO: implement ignore/silent catch for unreadable? - # Mostly based off the logic in the builtin pkgutil.iter_modules importer + # Mostly based off the logic in the builtin pkgutil.iter_modules importer. + # Only difference is we don't check if dirs contains __init__. # https://github.com/python/cpython/blob/fda056e64bdfcac3dd3d13eebda0a24994d83cb8/Lib/pkgutil.py#L130-L168 for path in paths: if not os.path.isdir(path): @@ -1252,30 +1253,20 @@ def _iter_modules_impl(paths, prefix=''): mod_path = os.path.join(path, basename) ispkg = False + if not modname and os.path.isdir(mod_path) and '.' not in basename: + # exclude things that obviously aren't Python package dirs + # FIXME: this dir is adjustable in py3.8+, check for it + if basename == '__pycache__': + continue - ispkg = ( - not modname and - os.path.isdir(mod_path) and - '.' not in basename and - _is_dir_a_pkg(mod_path) - ) + modname = basename + ispkg = True if modname and '.' not in modname: yielded.add(modname) yield prefix + modname, ispkg -def _is_dir_a_pkg(path: str) -> bool: - """Checks if the directory is a Python package (contains __init__).""" - with os.scandir(path) as scandir_it: - for entry in scandir_it: - subname = inspect.getmodulename(entry.name) - if subname == '__init__': - return True - - return False - - def _get_collection_metadata(collection_name): collection_name = _to_text(collection_name) if not collection_name or not isinstance(collection_name, str) or len(collection_name.split('.')) != 2: