# Copyright (c) Meta Platforms, Inc. and affiliates. # All rights reserved. # # This source code is licensed under the license found in the # LICENSE file in the root directory of this source tree. import os.path as osp import subprocess def is_installed(package: str) -> bool: """Check package whether installed. Args: package (str): Name of package to be checked. """ # When executing `import mmengine.runner`, # pkg_resources will be imported and it takes too much time. # Therefore, import it in function scope to save time. import importlib.util import pkg_resources from pkg_resources import get_distribution # refresh the pkg_resources # more datails at https://github.com/pypa/setuptools/issues/373 importlib.reload(pkg_resources) try: get_distribution(package) return True except pkg_resources.DistributionNotFound: spec = importlib.util.find_spec(package) if spec is None: return False elif spec.origin is not None: return True else: return False def get_installed_path(package: str) -> str: """Get installed path of package. Args: package (str): Name of package. Example: >>> get_installed_path('mmcls') >>> '.../lib/python3.7/site-packages/mmcls' """ import importlib.util from pkg_resources import DistributionNotFound, get_distribution # if the package name is not the same as module name, module name should be # inferred. For example, mmcv-full is the package name, but mmcv is module # name. If we want to get the installed path of mmcv-full, we should concat # the pkg.location and module name try: pkg = get_distribution(package) except DistributionNotFound as e: # if the package is not installed, package path set in PYTHONPATH # can be detected by `find_spec` spec = importlib.util.find_spec(package) if spec is not None: if spec.origin is not None: return osp.dirname(spec.origin) else: # `get_installed_path` cannot get the installed path of # namespace packages raise RuntimeError( f'{package} is a namespace package, which is invalid ' 'for `get_install_path`') else: raise e possible_path = osp.join(pkg.location, package) if osp.exists(possible_path): return possible_path else: return osp.join(pkg.location, package2module(package)) def package2module(package: str): """Infer module name from package. Args: package (str): Package to infer module name. """ from pkg_resources import get_distribution pkg = get_distribution(package) if pkg.has_metadata('top_level.txt'): module_name = pkg.get_metadata('top_level.txt').split('\n')[0] return module_name else: raise ValueError(f'can not infer the module name of {package}') def call_command(cmd: list) -> None: try: subprocess.check_call(cmd) except Exception as e: raise e # type: ignore def install_package(package: str): if not is_installed(package): call_command(['python', '-m', 'pip', 'install', package])