Beispiel #1
0
def check_installed(name: str = __package__) -> bool:
    try:
        from importlib.metadata import Distribution, PackageNotFoundError  # noqa
    except ImportError:
        try:
            from importlib_metadata import Distribution, PackageNotFoundError  # noqa
        except ImportError:
            # Should not get here EVER, but just in case lets just try checking pip freeze instead
            result, output = subprocess.getstatusoutput(
                [f"{sys.executable} -m pip freeze"])
            if result != 0:  # Not Ok
                return False
            is_installed = name in [
                requirement.split("==")[0]
                for requirement in output.splitlines()
            ]
            if name != "sickchill" or (name == "sickchill" and is_installed):
                logger.debug(f"{name} installed: {is_installed}")
            return is_installed

    try:
        Distribution.from_name(name)
        logger.debug(f"{name} installed: True")
    except PackageNotFoundError:
        if name != "sickchill":
            logger.debug(f"{name} installed: False")
        return False
    return True
Beispiel #2
0
    def test_package_not_found_mentions_metadata(self):
        # When a package is not found, that could indicate that the
        # packgae is not installed or that it is installed without
        # metadata. Ensure the exception mentions metadata to help
        # guide users toward the cause. See #124.
        with self.assertRaises(PackageNotFoundError) as ctx:
            Distribution.from_name('does-not-exist')

        assert "metadata" in str(ctx.exception)
Beispiel #3
0
def check_installed():
    try:
        from importlib.metadata import Distribution, PackageNotFoundError
    except ImportError:
        from importlib_metadata import Distribution, PackageNotFoundError

    try:
        Distribution.from_name('sickchill')
    except PackageNotFoundError:
        return False
    return True
Beispiel #4
0
def test_coherence_of_get_modules() -> None:
    for package in PACKAGES:
        dist = Distribution.from_name(package)
        lhs = _get_modules_by_toplevel_txt(dist)
        rhs = _get_modules_by_files(dist)
        if lhs is not None:
            assert set(lhs) == set(rhs)
Beispiel #5
0
def get_pkg_paths(pkg: Distribution) -> t.List[Path]:
    # Some egg-info packages have e.g. src/ paths in their SOURCES.txt file,
    # but they also have this:
    mods = set((pkg.read_text("top_level.txt") or "").split())
    if not mods and pkg.files:
        # Fall back to RECORD file for dist-info packages without top_level.txt
        mods = {
            f.parts[0] if len(f.parts) > 1 else f.with_suffix("").name
            for f in pkg.files
            if f.suffix == ".py" or Path(pkg.locate_file(f)).is_symlink()
        }
    if not mods:
        raise RuntimeError(
            f"Can’t determine top level packages of {pkg.metadata['Name']}"
        )
    return [Path(pkg.locate_file(mod)) for mod in mods]
    def test_more_complex_deps_requires_text(self):
        requires = textwrap.dedent("""
            dep1
            dep2

            [:python_version < "3"]
            dep3

            [extra1]
            dep4

            [extra2:python_version < "3"]
            dep5
            """)
        deps = sorted(Distribution._deps_from_requires_text(requires))
        expected = [
            'dep1',
            'dep2',
            'dep3; python_version < "3"',
            'dep4; extra == "extra1"',
            'dep5; (python_version < "3") and extra == "extra2"',
        ]
        # It's important that the environment marker expression be
        # wrapped in parentheses to avoid the following 'and' binding more
        # tightly than some other part of the environment expression.

        assert deps == expected
Beispiel #7
0
def get_installed_packages():
    """ get a list of all packages currently installed in the active environment """
    packages = []

    pool = Pool(4)

    # for dist in track(
    #     list(Distribution.discover()), description="[cyan]Grabbing dependency info"
    # ):
    #     packages.append(Package.from_dist(dist))

    dists = list(Distribution.discover())
    dists_num = len(dists)

    log.info("[bold]Found a total of {} distributions".format(dists_num),
             extra={"markup": True})

    for package_enum in enumerate(pool.imap(Package.from_dist, dists),
                                  start=1):
        package = package_enum[1]
        log.info("{0}/{1}: processed [bold cyan]{2} {3}[/bold cyan]".format(
            package_enum[0], dists_num, package.name, package.version),
                 extra={"markup": True})
        packages.append(package)

    return packages
Beispiel #8
0
    def __init__(self, config: ChrispileConfig):
        pkg = Distribution.from_name(__package__)
        eps = [ep for ep in pkg.entry_points if ep.group == 'console_scripts']
        self.program_name = eps[0].name

        jinja_env = Environment(loader=PackageLoader(__package__, 'templates'))
        self.template = jinja_env.get_template('exec.sh')
        self.config = config
Beispiel #9
0
 def test_find_distributions_specified_path(self):
     dists = itertools.chain.from_iterable(
         resolver(path=[str(self.site_dir)])
         for resolver in Distribution._discover_resolvers()
         )
     assert any(
         dist.metadata['Name'] == 'distinfo-pkg'
         for dist in dists
         )
Beispiel #10
0
 def _find_entry_point(self, app: str) -> Optional[EntryPoint]:
     if not self.python_path.exists():
         return None
     dists = Distribution.discover(
         name=self.main_package_name,
         path=[str(get_site_packages(self.python_path))])
     for dist in dists:
         for ep in dist.entry_points:
             if ep.group == "pipx.run" and ep.name == app:
                 return ep
     return None
Beispiel #11
0
def get_apps(dist: metadata.Distribution, bin_path: Path) -> List[str]:
    apps = set()

    sections = {"console_scripts", "gui_scripts"}
    # "entry_points" entry in setup.py are found here
    for ep in dist.entry_points:
        if ep.group not in sections:
            continue
        if (bin_path / ep.name).exists():
            apps.add(ep.name)
        if WINDOWS and (bin_path / (ep.name + ".exe")).exists():
            # WINDOWS adds .exe to entry_point name
            apps.add(ep.name + ".exe")

    # search installed files
    # "scripts" entry in setup.py is found here (test w/ awscli)
    for path in dist.files or []:
        # vast speedup by ignoring all paths not above distribution root dir
        #   (venv/bin or venv/Scripts is above distribution root)
        if Path(path).parts[0] != "..":
            continue

        dist_file_path = Path(dist.locate_file(path))
        try:
            if dist_file_path.parent.samefile(bin_path):
                apps.add(path.name)
        except FileNotFoundError:
            pass

    # not sure what is found here
    inst_files = dist.read_text("installed-files.txt") or ""
    for line in inst_files.splitlines():
        entry = line.split(",")[0]  # noqa: T484
        inst_file_path = Path(dist.locate_file(entry)).resolve()
        try:
            if inst_file_path.parent.samefile(bin_path):
                apps.add(inst_file_path.name)
        except FileNotFoundError:
            pass

    return sorted(apps)
Beispiel #12
0
 def from_dist(cls, dist: Distribution) -> "Requirement":
     direct_url_json = dist.read_text("direct_url.json")
     if direct_url_json is not None:
         direct_url = json.loads(direct_url_json)
         data = {
             "name": dist.metadata["Name"],
             "url": direct_url.get("url"),
             "editable": direct_url.get("dir_info", {}).get("editable"),
             "subdirectory": direct_url.get("subdirectory"),
         }
         if "vcs_info" in direct_url:
             vcs_info = direct_url["vcs_info"]
             data.update(
                 url=f"{vcs_info['vcs']}+{direct_url['url']}",
                 ref=vcs_info.get("requested_revision"),
                 revision=vcs_info.get("commit_id"),
             )
             return VcsRequirement.create(**data)
         return FileRequirement.create(**data)
     return NamedRequirement.create(name=dist.metadata["Name"],
                                    version=f"=={dist.version}")
Beispiel #13
0
 def test_retrieves_version_of_self(self):
     dist = Distribution.from_name('distinfo-pkg')
     assert isinstance(dist.version, str)
     assert re.match(self.version_pattern, dist.version)
Beispiel #14
0
    def create_production_scripts(self, tool, venv_session):
        """Create Rez production used binary scripts

        The binary script will be executed with Python interpreter flag -E,
        which will ignore all PYTHON* env vars, e.g. PYTHONPATH and PYTHONHOME.

        """
        _log.info("Generating production scripts..")

        site_packages = venv_session.creator.purelib
        bin_path = venv_session.creator.bin_dir

        if tool.edit:
            egg_link = site_packages / ("%s.egg-link" % tool.name)
            if not egg_link.is_file():
                _log.error("Tool %r installed in edit mode, but unable "
                           "to find egg-link for generating production "
                           "scripts from source. File not exists: %s" %
                           (tool.name, egg_link))
                return

            with open(str(egg_link), "r") as f:
                package_location = f.readline().strip()
            path = [str(package_location)]
        else:
            path = [str(site_packages)]

        dists = Distribution.discover(name=tool.name, path=path)
        specifications = {
            ep.name: "{ep.name} = {ep.value}".format(ep=ep)
            for dist in dists for ep in dist.entry_points
            if ep.group == "console_scripts"
        }

        # delete bin files written into virtualenv
        # this also avoided naming conflict between script 'rez' and dir 'rez'
        for script_name in specifications.keys():
            script_path = bin_path / script_name
            if script_path.is_file():
                os.remove(str(script_path))

        venv_name = tool.name if tool.isolation else "rez"
        prod_bin_path = self._revision.production_bin_dir(venv_name)
        makedirs(prod_bin_path)

        maker = ScriptMaker(source_dir=None, target_dir=str(prod_bin_path))
        maker.executable = str(venv_session.creator.exe)

        # Align with wheel
        #
        # Ensure we don't generate any variants for scripts because this is
        # almost never what somebody wants.
        # See https://bitbucket.org/pypa/distlib/issue/35/
        maker.variants = {""}
        # Ensure old scripts are overwritten.
        # See https://github.com/pypa/pip/issues/1800
        maker.clobber = True
        # This is required because otherwise distlib creates scripts that are
        # not executable.
        # See https://bitbucket.org/pypa/distlib/issue/32/
        maker.set_mode = True

        if self._rez_in_edit:
            # Allow pre-caching rez_bin_path on script entry if environ var
            # `REZUP_EDIT_IN_PRODUCTION` is set with non-empty value.
            # See https://github.com/davidlatwe/rezup/pull/56
            maker.script_template = r'''# -*- coding: utf-8 -*-
import re
import os
import sys
from %(module)s import %(import_name)s
if os.getenv("REZUP_EDIT_IN_PRODUCTION"):
    from rez.system import system
    setattr(system, 'rez_bin_path', r'{rez_bin_path}')
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(%(func)s())
'''.format(rez_bin_path=str(prod_bin_path))

        scripts = maker.make_multiple(
            specifications=specifications.values(),
            options=dict(interpreter_args=list(tool.flags)))

        return scripts
 def test_distribution_at_str(self):
     dist_info_path = self.site_dir / 'distinfo_pkg-1.0.0.dist-info'
     dist = Distribution.at(str(dist_info_path))
     assert dist.version == '1.0.0'
 def test_distribution_at_pathlib(self):
     """Demonstrate how to load metadata direct from a directory."""
     dist_info_path = self.site_dir / 'distinfo_pkg-1.0.0.dist-info'
     dist = Distribution.at(dist_info_path)
     assert dist.version == '1.0.0'
 def test_find_distributions_specified_path(self):
     dists = Distribution.discover(path=[str(self.site_dir)])
     assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists)
Beispiel #18
0
 def test_invalid_inputs_to_from_name(self, name):
     with self.assertRaises(Exception):
         Distribution.from_name(name)
def _get_modules_by_toplevel_txt(dist: Distribution) -> Optional[List[str]]:
    modules = dist.read_text("top_level.txt")
    if modules is None:
        return None
    else:
        return modules.rstrip().split("\n")
def _get_modules(project_name: str) -> List[str]:
    dist = Distribution.from_name(project_name)
    return _get_modules_by_toplevel_txt(dist) or _get_modules_by_files(dist)
Beispiel #21
0
def list_engines():
    entrypoints = (
        entry_point
        for entry_point in Distribution.from_name("xarray").entry_points
        if entry_point.module == "xarray.backends")
    return build_engines(entrypoints)
Beispiel #22
0
 def test_for_name_does_not_exist(self):
     with self.assertRaises(PackageNotFoundError):
         Distribution.from_name('does-not-exist')
Beispiel #23
0
 def __init__(self, metadata, *args, **kwargs):
     Distribution.__init__(self, *args, **kwargs)
     self._data = metadata
Beispiel #24
0
    def __init__(cls, name, bases, d):
        if 'PACKAGE' in d:
            # interrogate setup.py to automatically fill in some
            # class attributes for the subclass
            autofill = [
                'AUTHORS', 'DESCRIPTION', 'LICENSE', 'DOCUMENTATION', 'VERSION'
            ]
            for attr in autofill:
                if attr in d:
                    raise ValueError(
                        'Do not manually set value value for '
                        f'"{attr}" when "PACKAGE={d["PACKAGE"]}" is declared')

            pkg = Distribution.from_name(d['PACKAGE'])
            setup = pkg.metadata
            if 'TITLE' not in d:
                cls.TITLE = setup['name']
                d['TITLE'] = cls.TITLE
            cls.AUTHORS = f'{setup["author"]} <{setup["author-email"]}>'
            d['AUTHORS'] = cls.AUTHORS
            cls.DESCRIPTION = setup['summary']
            d['DESCRIPTION'] = cls.DESCRIPTION
            cls.LICENSE = setup['license']
            d['LICENSE'] = cls.LICENSE
            cls.DOCUMENTATION = setup['home-page']
            d['DOCUMENTATION'] = cls.DOCUMENTATION
            cls.VERSION = setup['version']
            d['VERSION'] = cls.VERSION

            if 'SELFEXEC' not in d:
                eps = [
                    ep for ep in pkg.entry_points
                    if ep.group == 'console_scripts'
                ]
                if eps:
                    if len(eps) > 1:
                        # multiple console_scripts found but maybe
                        # they're just the same thing
                        different_scripts = [
                            ep for ep in eps if ep.value != eps[0].value
                        ]
                        if different_scripts:
                            raise ValueError(
                                'SELFEXEC not defined and more than one '
                                'console_scripts found')
                    cls.SELFEXEC = eps[0].name
                    d['SELFEXEC'] = cls.SELFEXEC
                    cls.EXECSHELL = sys.executable
                    d['EXECSHELL'] = cls.EXECSHELL
                    script_location = shutil.which(cls.SELFEXEC)
                    if not script_location:
                        raise EnvironmentError(
                            cls.SELFEXEC +
                            ' not found in PATH - check your SELFEXEC')
                    cls.SELFPATH = os.path.dirname(script_location)
                    d['SELFPATH'] = cls.SELFPATH

            script_location = os.path.join(cls.SELFPATH, cls.SELFEXEC)
            if not os.path.isfile(script_location):
                raise EnvironmentError(
                    script_location +
                    ' not found - check your SELFPATH, SELFEXEC')

        # class variables to be enforced in the subclasses
        attrs = [
            'DESCRIPTION', 'TYPE', 'TITLE', 'LICENSE', 'AUTHORS', 'VERSION',
            'SELFPATH', 'SELFEXEC', 'EXECSHELL'
        ]
        for attr in attrs:
            if attr not in d:
                raise ValueError(
                    f"Class {name} doesn't define {attr} class variable")
            if type(d[attr]) is not str:
                raise ValueError(f'{attr} ({type(attr)}) must be a string')
        if 'OUTPUT_META_DICT' not in d:
            raise ValueError(f"Class {name} doesn't define OUTPUT_META_DICT")
        if type(d['OUTPUT_META_DICT']) is not dict:
            raise ValueError('OUTPUT_META_DICT must be dict')
        type.__init__(cls, name, bases, d)
Beispiel #25
0
def _mock_importlib_distributions():
    return (Distribution.at(p) for p in WHEEL_BASE.glob("*.dist-info")
            )  # type: ignore[union-attr]