"""
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
[docs]
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__)
[docs]
def loadTestsFromName(self, event):
"""Load tests from module named by event.name"""
return discovery.Discoverer.loadTestsFromName(self, event)
[docs]
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)