[docs]classImportExtensions:""" A context manager for wrapping extension import and fallback. It guides the user to pip install correct package by looking up extra-requirements.txt. :param required: set to True if you want to raise the ModuleNotFound error :param logger: when not given, built-in warnings.warn will be used :param help_text: the help text followed after :param pkg_name: the package name to find in extra_requirements.txt, when not given the ModuleNotFound exec_val will be used as the best guess """def__init__(self,required:bool,logger=None,help_text:Optional[str]=None,pkg_name:Optional[str]=None,verbose:bool=True,):self._required=requiredself._tags=[]self._help_text=help_textself._logger=loggerself._pkg_name=pkg_nameself._verbose=verbosedef__enter__(self):returnselfdef__exit__(self,exc_type,exc_val,traceback):ifexc_type==ModuleNotFoundError:missing_module=self._pkg_nameorexc_val.namewithopen(os.path.join(__resources_path__,'extra-requirements.txt'))asfp:forvinfp:if(v.strip()andnotv.startswith('#')andv.startswith(missing_module)and':'inv):missing_module,install_tags=v.split(':')self._tags.append(missing_module)self._tags.extend(vv.strip()forvvininstall_tags.split(','))breakifself._tags:fromjina.helperimportcoloredreq_msg=colored('fallback to default behavior',color='yellow')ifself._required:req_msg=colored('and it is required',color='red')err_msg=f'''Python package "{colored(missing_module,attrs='bold')}" is not installed, {req_msg}. You are trying to use a feature not enabled by your current Jina installation.'''avail_tags=' '.join(colored(f'[{tag}]',attrs='bold')fortaginself._tags)err_msg+=(f'\n\nTo enable this feature, use {colored("pip install jina[TAG]",attrs="bold")}, 'f'where {colored("[TAG]",attrs="bold")} is one of {avail_tags}.\n')else:err_msg=f'{exc_val.msg}'ifself._required:ifself._verbose:ifself._logger:self._logger.critical(err_msg)ifself._help_text:self._logger.error(self._help_text)else:warnings.warn(err_msg,RuntimeWarning,stacklevel=2)raiseexc_valelse:ifself._verbose:ifself._logger:self._logger.warning(err_msg)ifself._help_text:self._logger.info(self._help_text)else:warnings.warn(err_msg,RuntimeWarning,stacklevel=2)returnTrue# suppress the error
def_path_import(absolute_path:str):importimportlib.utiltry:# I dont want to trust user path based on directory structure, "user_module", perioddefault_spec_name='user_module'user_module_name=os.path.splitext(os.path.basename(absolute_path))[0]ifuser_module_name=='__init__':# __init__ can not be used as a module namespec_name=default_spec_nameelifuser_module_namenotinsys.modules:spec_name=user_module_nameelse:warnings.warn(f'''{user_module_name} shadows one of built-in Python module name. It is imported as `{default_spec_name}.{user_module_name}` Affects: - Either, change your code from using `from {user_module_name} import ...` to `from {default_spec_name}.{user_module_name} import ...` - Or, rename {user_module_name} to another name ''')spec_name=f'{default_spec_name}.{user_module_name}'spec=importlib.util.spec_from_file_location(spec_name,absolute_path)module=importlib.util.module_from_spec(spec)sys.modules[spec_name]=modulespec.loader.exec_module(module)exceptExceptionasex:raiseImportError(f'can not import module from {absolute_path}')fromex
[docs]classPathImporter:"""The class to import modules from paths."""
[docs]@staticmethoddefadd_modules(*paths):""" Import modules from paths. :param paths: Paths of the modules. """fromjina.jaml.helperimportcomplete_pathpaths=[complete_path(m)forminpaths]forpinpaths:ifnotos.path.exists(p):raiseFileNotFoundError(f'cannot import module from {p}, file not exist')_path_import(p)