# Source code for nose2.plugins.loader.eggdiscovery

    """
    Egg-based discovery test loader.

    This plugin implements nose2's automatic test module discovery inside Egg Files.
    It looks for test modules in packages whose names start
    with ``test``, then fires the :func:`loadTestsFromModule` hook for each
    one to allow other plugins to load the actual tests.

    It also fires :func:`handleFile` for every file that it sees, and
    :func:`matchPath` for every Python module, to allow other plugins to
    load tests from other kinds of files and to influence which modules
    are examined for tests.

    """

    from __future__ import annotations

    import logging
    import os

    from nose2 import events
    from nose2.plugins.loader import discovery

    __unittest = True
    log = logging.getLogger(__name__)

    try:
        import pkg_resources

        _has_pkg_resources = True
    except ImportError:
        _has_pkg_resources = False

    class EggDiscoveryLoader(events.Plugin, discovery.Discoverer):
        """Loader plugin that can discover tests inside Egg Files"""

        alwaysOn = True
        configSection = "discovery"

        def registerInSubprocess(self, event):
            event.pluginClasses.append(self.__class__)

        def loadTestsFromName(self, event):
            """Load tests from module named by event.name"""
            return discovery.Discoverer.loadTestsFromName(self, event)

        def loadTestsFromNames(self, event):
            """Discover tests if no test names specified"""
            return discovery.Discoverer.loadTestsFromNames(self, event)

        def _checkIfPathIsOK(self, start_dir):
            if not os.path.exists(os.path.abspath(start_dir)):
                raise OSError("%s does not exist" % os.path.abspath(start_dir))

        def _find_tests_in_egg_dir(self, event, rel_path, dist):
            log.debug(
                "find in egg dir %s %s (%s)", dist.location, rel_path, dist.project_name
            )
            full_path = os.path.join(dist.location, rel_path)
            dir_handler = discovery.DirectoryHandler(self.session)
            yield from dir_handler.handle_dir(event, full_path, dist.location)
            if dir_handler.event_handled:
                return
            for path in dist.resource_listdir(rel_path):
                # on setuptools==38.2.5 , resource_listdir() can yield ""
                # if that happens, skip processing it to avoid infinite recursion
                if path == "":
                    continue

                entry_path = os.path.join(rel_path, path)
                if dist.resource_isdir(entry_path):
                    yield from self._find_tests_in_egg_dir(event, entry_path, dist)
                else:
                    modname = os.path.splitext(entry_path)[0].replace(os.sep, ".")
                    yield from self._find_tests_in_file(
                        event,
                        path,
                        os.path.join(dist.location, entry_path),
                        dist.location,
                        modname,
                    )

        def _find_tests_in_dir(self, event, full_path, top_level):
            if os.path.exists(full_path):
                return
            elif _has_pkg_resources and full_path.find(".egg") != -1:
                egg_path = full_path.split(".egg")[0] + ".egg"
                for dist in pkg_resources.find_distributions(egg_path):
                    for modname in dist._get_metadata("top_level.txt"):
                        yield from self._find_tests_in_egg_dir(event, modname, dist)