def _get_distributions(objs, py_dir, logger, observer):
    """ Return (distributions, local_modules, orphans) used by objs. """
    distributions = set()
    local_modules = set()
    orphans = set()
    modules = set(['__builtin__'])
    prefixes = set()
    not_found = set()

    if _get_distributions.excludes is None:
        # Exclude Python standard library from ModuleFinder analysis.
        _get_distributions.excludes = _get_standard_modules()

    for obj, container, index in objs:
        try:
            name = obj.__module__
        except AttributeError:
            continue
        if name is None or name in modules:
            continue
        modules.add(name)

        # Skip modules in distributions we already know about.
        try:
            path = os.path.realpath(sys.modules[name].__file__)
        except AttributeError:
            logger.log(LOG_DEBUG2, '    module %s has no __file__', name)
            continue

        if sys.platform == 'win32':  # pragma no cover
            orig_path = path
            path = path.lower()

        found = False
        for prefix in prefixes:
            if path.startswith(prefix):
                found = True
                break
        if found:
            continue

        if sys.platform == 'win32':  # pragma no cover
            path = orig_path

        egg = path.find('.egg')
        if egg > 0:
            # We'll assume the egg has accurate dependencies.
            path = path[:egg+4]
            _process_egg(path, distributions, prefixes, logger)
        else:
            # Use ModuleFinder to get the modules this object requires.
            if path.endswith('.pyc') or path.endswith('.pyo'):
                path = path[:-1]
            # Just being defensive.
            if not os.path.exists(path):  #pragma no cover
                logger.warning("    module path '%s' does not exist", path)
                continue

            if not os.path.isabs(path):
                path = os.path.join(os.getcwd(), path)

            finder_info = None
            try:
                finder_info = _DistCache.lookup(path)
            except KeyError:
                observer.analyze(path)
                finder = modulefinder.ModuleFinder(
                                          excludes=_get_distributions.excludes)
                try:
                    finder.run_script(path)
                # Just being defensive.
                except Exception:  #pragma no cover
                    logger.exception("ModuleFinder for '%s'" % path)
                    # Note dependency, even if for some reason ModuleFinder
                    # can't handle it.
                    name, dot, ext = os.path.basename(path).partition('.')
                    finder_info = [(name, path)]
                else:
                    finder_info = []
                    for name, module in finder.modules.items():
                        try:
                            filename = module.__file__
                        # Just defensive, ModuleFinder should exclude these.
                        except AttributeError:  #pragma no cover
                            filename = None
                        finder_info.append((name, filename))
                    _DistCache.record(path, finder_info)
            else:
                logger.log(LOG_DEBUG2, "    reusing analysis of '%s'", path)

            if finder_info:
                _process_found_modules(py_dir, finder_info, modules,
                                       distributions, prefixes, local_modules,
                                       orphans, not_found, logger)
    _DistCache.save()
    distributions = sorted(distributions, key=lambda dist: dist.project_name)
    logger.log(LOG_DEBUG2, '    required distributions:')
    for dist in distributions:
        logger.log(LOG_DEBUG2, '        %s %s', dist.project_name, dist.version)
    return (distributions, local_modules, orphans)
dataset/ETHPy150Open OpenMDAO/OpenMDAO-Framework/openmdao.util/src/openmdao/util/eggsaver.py/_get_distributions/original