def find_extra_reqs(options):
    # 1. find files used by imports in the code (as best we can without
    #    executing)
    used_modules = common.find_imported_modules(options)

    # 2. find which packages provide which files
    installed_files = {}
    all_pkgs = (pkg.project_name for pkg in get_installed_distributions())
    for package in search_packages_info(all_pkgs):
        log.debug("installed package: %s (at %s)", package["name"], package["location"])
        for f in package.get("files", []):
            path = os.path.realpath(os.path.join(package["location"], f))
            installed_files[path] = package["name"]
            package_path = common.is_package_file(path)
            if package_path:
                # we've seen a package file so add the bare package directory
                # to the installed list as well as we might want to look up
                # a package by its directory path later
                installed_files[package_path] = package["name"]

    # 3. match imported modules against those packages
    used = collections.defaultdict(list)
    for modname, info in used_modules.items():
        # probably standard library if it's not in the files list
        if info.filename in installed_files:
            used_name = canonicalize_name(installed_files[info.filename])
            log.debug("used module: %s (from package %s)", modname, installed_files[info.filename])
            used[used_name].append(info)
        else:
            log.debug("used module: %s (from file %s, assuming stdlib or local)", modname, info.filename)

    # 4. compare with requirements.txt
    explicit = common.find_required_modules(options)

    return [name for name in explicit if name not in used]
Example #2
0
def test_find_required_modules(monkeypatch, tmp_path: Path):
    class options:
        skip_incompatible = False

    options.ignore_reqs = common.ignorer(ignore_cfg=['barfoo'])

    fake_requirements_file = tmp_path / 'requirements.txt'
    fake_requirements_file.write_text('foobar==1\nbarfoo==2')

    reqs = common.find_required_modules(
        options=options,
        requirements_filename=str(fake_requirements_file),
    )
    assert reqs == set(['foobar'])
def test_find_required_modules(monkeypatch):
    class options:
        @staticmethod
        def ignore_reqs(req):
            if req.name == 'barfoo':
                return True
            return False

    FakeReq = collections.namedtuple('FakeReq', ['name'])
    requirements = [FakeReq('foobar'), FakeReq('barfoo')]
    monkeypatch.setattr(common, 'parse_requirements',
        pretend.call_recorder(lambda a, session=None: requirements))

    reqs = common.find_required_modules(options)
    assert reqs == set(['foobar'])
Example #4
0
def test_find_required_modules(monkeypatch):
    class options:
        @staticmethod
        def ignore_reqs(req):
            if req.name == 'barfoo':
                return True
            return False

    FakeReq = collections.namedtuple('FakeReq', ['name'])
    requirements = [FakeReq('foobar'), FakeReq('barfoo')]
    monkeypatch.setattr(
        common, 'parse_requirements',
        pretend.call_recorder(lambda a, session=None: requirements))

    reqs = common.find_required_modules(options)
    assert reqs == set(['foobar'])
Example #5
0
def test_find_required_modules_env_markers(monkeypatch, tmp_path):
    class options:
        skip_incompatible = True

        def ignore_reqs(self, modname):
            return False

    fake_requirements_file = tmp_path / 'requirements.txt'
    fake_requirements_file.write_text('spam==1; python_version<"2.0"\n'
                                      'ham==2;\n'
                                      'eggs==3\n')

    reqs = common.find_required_modules(
        options=options(),
        requirements_filename=str(fake_requirements_file),
    )
    assert reqs == {'ham', 'eggs'}
def find_extra_reqs(options, requirements_filename):
    # 1. find files used by imports in the code (as best we can without
    #    executing)
    used_modules = common.find_imported_modules(options)

    # 2. find which packages provide which files
    installed_files = {}
    all_pkgs = (pkg.project_name for pkg in get_installed_distributions())
    for package in search_packages_info(all_pkgs):
        log.debug('installed package: %s (at %s)', package['name'],
                  package['location'])
        for package_file in package.get('files', []) or []:
            path = os.path.realpath(
                os.path.join(package['location'], package_file),
            )
            installed_files[path] = package['name']
            package_path = common.is_package_file(path)
            if package_path:
                # we've seen a package file so add the bare package directory
                # to the installed list as well as we might want to look up
                # a package by its directory path later
                installed_files[package_path] = package['name']

    # 3. match imported modules against those packages
    used = collections.defaultdict(list)
    for modname, info in used_modules.items():
        # probably standard library if it's not in the files list
        if info.filename in installed_files:
            used_name = canonicalize_name(installed_files[info.filename])
            log.debug('used module: %s (from package %s)', modname,
                      installed_files[info.filename])
            used[used_name].append(info)
        else:
            log.debug(
                'used module: %s (from file %s, assuming stdlib or local)',
                modname, info.filename)

    # 4. compare with requirements.txt
    explicit = common.find_required_modules(
        options=options,
        requirements_filename=requirements_filename,
    )

    return [name for name in explicit if name not in used]
Example #7
0
def find_extra_reqs(options, requirements_filename):
    # 1. find files used by imports in the code (as best we can without
    #    executing)
    used_modules = common.find_imported_modules(options)

    # 2. find which packages provide which files
    installed_files = {}
    all_pkgs = (pkg.project_name for pkg in get_installed_distributions())
    for package in search_packages_info(all_pkgs):
        if isinstance(package, dict):  # pragma: no cover
            package_name = package['name']
            package_location = package['location']
            package_files = package.get('files', []) or []
        else:  # pragma: no cover
            package_name = package.name
            package_location = package.location
            package_files = []
            for item in (package.files or []):
                here = pathlib.Path('.').resolve()
                item_location_rel = (pathlib.Path(package_location) / item)
                item_location = item_location_rel.resolve()
                try:
                    relative_item_location = item_location.relative_to(here)
                except ValueError:
                    # Ideally we would use Pathlib.is_relative_to rather than
                    # checking for a ValueError, but that is only available in
                    # Python 3.9+.
                    relative_item_location = item_location
                package_files.append(str(relative_item_location))

        log.debug('installed package: %s (at %s)', package_name,
                  package_location)
        for package_file in package_files:
            path = os.path.realpath(
                os.path.join(package_location, package_file),
            )
            installed_files[path] = package_name
            package_path = common.is_package_file(path)
            if package_path:
                # we've seen a package file so add the bare package directory
                # to the installed list as well as we might want to look up
                # a package by its directory path later
                installed_files[package_path] = package_name

    # 3. match imported modules against those packages
    used = collections.defaultdict(list)

    for modname, info in used_modules.items():
        # probably standard library if it's not in the files list
        if info.filename in installed_files:
            used_name = canonicalize_name(installed_files[info.filename])
            log.debug('used module: %s (from package %s)', modname,
                      installed_files[info.filename])
            used[used_name].append(info)
        else:
            log.debug(
                'used module: %s (from file %s, assuming stdlib or local)',
                modname, info.filename)

    # 4. compare with requirements
    explicit = common.find_required_modules(
        options=options,
        requirements_filename=requirements_filename,
    )

    return [name for name in explicit if name not in used]