The import name of the module to reference for the alias
required
callback
A function to call when the alias module is loaded
required
Source code in src/prefect/utilities/importtools.py
295296297298299300301302303304305306307
classAliasedModuleDefinition(NamedTuple):""" A definition for the `AliasedModuleFinder`. Args: alias: The import name to create real: The import name of the module to reference for the alias callback: A function to call when the alias module is loaded """alias:strreal:strcallback:Optional[Callable[[str],None]]
classAliasedModuleFinder(MetaPathFinder):def__init__(self,aliases:Iterable[AliasedModuleDefinition]):""" See `AliasedModuleDefinition` for alias specification. Aliases apply to all modules nested within an alias. """self.aliases=aliasesdeffind_spec(self,fullname:str,path=None,target=None,)->Optional[ModuleSpec]:""" The fullname is the imported path, e.g. "foo.bar". If there is an alias "phi" for "foo" then on import of "phi.bar" we will find the spec for "foo.bar" and create a new spec for "phi.bar" that points to "foo.bar". """foralias,real,callbackinself.aliases:iffullname.startswith(alias):# Retrieve the spec of the real modulereal_spec=importlib.util.find_spec(fullname.replace(alias,real,1))# Create a new spec for the aliasreturnModuleSpec(fullname,AliasedModuleLoader(fullname,callback,real_spec),origin=real_spec.origin,is_package=real_spec.submodule_search_locationsisnotNone,)
The fullname is the imported path, e.g. "foo.bar". If there is an alias "phi"
for "foo" then on import of "phi.bar" we will find the spec for "foo.bar" and
create a new spec for "phi.bar" that points to "foo.bar".
Source code in src/prefect/utilities/importtools.py
deffind_spec(self,fullname:str,path=None,target=None,)->Optional[ModuleSpec]:""" The fullname is the imported path, e.g. "foo.bar". If there is an alias "phi" for "foo" then on import of "phi.bar" we will find the spec for "foo.bar" and create a new spec for "phi.bar" that points to "foo.bar". """foralias,real,callbackinself.aliases:iffullname.startswith(alias):# Retrieve the spec of the real modulereal_spec=importlib.util.find_spec(fullname.replace(alias,real,1))# Create a new spec for the aliasreturnModuleSpec(fullname,AliasedModuleLoader(fullname,callback,real_spec),origin=real_spec.origin,is_package=real_spec.submodule_search_locationsisnotNone,)
A fake module returned by lazy_import when the module cannot be found. When any
of the module's attributes are accessed, we will throw a ModuleNotFoundError.
classDelayedImportErrorModule(ModuleType):""" A fake module returned by `lazy_import` when the module cannot be found. When any of the module's attributes are accessed, we will throw a `ModuleNotFoundError`. Adapted from [lazy_loader][1] [1]: https://github.com/scientific-python/lazy_loader """def__init__(self,frame_data,help_message,*args,**kwargs):self.__frame_data=frame_dataself.__help_message=(help_messageor"Import errors for this module are only reported when used.")super().__init__(*args,**kwargs)def__getattr__(self,attr):ifattrin("__class__","__file__","__frame_data","__help_message"):super().__getattr__(attr)else:fd=self.__frame_dataraiseModuleNotFoundError(f"No module named '{fd['spec']}'\n\nThis module was originally imported"f" at:\n File \"{fd['filename']}\", line {fd['lineno']}, in"f" {fd['function']}\n\n{''.join(fd['code_context']).strip()}\n"+self.__help_message)
deffrom_qualified_name(name:str)->Any:""" Import an object given a fully-qualified name. Args: name: The fully-qualified name of the object to import. Returns: the imported object Examples: >>> obj = from_qualified_name("random.randint") >>> import random >>> obj == random.randint True """# Try importing it first so we support "module" or "module.sub_module"try:module=importlib.import_module(name)returnmoduleexceptImportError:# If no subitem was included raise the import errorif"."notinname:raise# Otherwise, we'll try to load it as an attribute of a modulemod_name,attr_name=name.rsplit(".",1)module=importlib.import_module(mod_name)returngetattr(module,attr_name)
defimport_object(import_path:str):""" Load an object from an import path. Import paths can be formatted as one of: - module.object - module:object - /path/to/script.py:object This function is not thread safe as it modifies the 'sys' module during execution. """if".py:"inimport_path:script_path,object_name=import_path.rsplit(":",1)module=load_script_as_module(script_path)else:if":"inimport_path:module_name,object_name=import_path.rsplit(":",1)elif"."inimport_path:module_name,object_name=import_path.rsplit(".",1)else:raiseValueError(f"Invalid format for object import. Received {import_path!r}.")module=load_module(module_name)returngetattr(module,object_name)
Create a lazily-imported module to use in place of the module of the given name.
Use this to retain module-level imports for libraries that we don't want to
actually import until they are needed.
deflazy_import(name:str,error_on_import:bool=False,help_message:str="")->ModuleType:""" Create a lazily-imported module to use in place of the module of the given name. Use this to retain module-level imports for libraries that we don't want to actually import until they are needed. Adapted from the [Python documentation][1] and [lazy_loader][2] [1]: https://docs.python.org/3/library/importlib.html#implementing-lazy-imports [2]: https://github.com/scientific-python/lazy_loader """try:returnsys.modules[name]exceptKeyError:passspec=importlib.util.find_spec(name)ifspecisNone:iferror_on_import:raiseModuleNotFoundError(f"No module named '{name}'.\n{help_message}")else:try:parent=inspect.stack()[1]frame_data={"spec":name,"filename":parent.filename,"lineno":parent.lineno,"function":parent.function,"code_context":parent.code_context,}returnDelayedImportErrorModule(frame_data,help_message,"DelayedImportErrorModule")finally:delparentmodule=importlib.util.module_from_spec(spec)sys.modules[name]=moduleloader=importlib.util.LazyLoader(spec.loader)loader.exec_module(module)returnmodule
Import a module with support for relative imports within the module.
Source code in src/prefect/utilities/importtools.py
173174175176177178179180181182183184185
defload_module(module_name:str)->ModuleType:""" Import a module with support for relative imports within the module. """# Ensure relative imports within the imported module work if the user is in the# correct working directoryworking_directory=os.getcwd()sys.path.insert(0,working_directory)try:returnimportlib.import_module(module_name)finally:sys.path.remove(working_directory)
If an exception occurs during execution of the script, a
prefect.exceptions.ScriptError is created to wrap the exception and raised.
During the duration of this function call, sys is modified to support loading.
These changes are reverted after completion, but this function is not thread safe
and use of it in threaded contexts may result in undesirable behavior.
See https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
Source code in src/prefect/utilities/importtools.py
defload_script_as_module(path:str)->ModuleType:""" Execute a script at the given path. Sets the module name to `__prefect_loader__`. If an exception occurs during execution of the script, a `prefect.exceptions.ScriptError` is created to wrap the exception and raised. During the duration of this function call, `sys` is modified to support loading. These changes are reverted after completion, but this function is not thread safe and use of it in threaded contexts may result in undesirable behavior. See https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly """# We will add the parent directory to search locations to support relative imports# during execution of the scriptifnotpath.endswith(".py"):raiseValueError(f"The provided path does not point to a python file: {path!r}")parent_path=str(Path(path).resolve().parent)working_directory=os.getcwd()spec=importlib.util.spec_from_file_location("__prefect_loader__",path,# Support explicit relative imports i.e. `from .foo import bar`submodule_search_locations=[parent_path,working_directory],)module=importlib.util.module_from_spec(spec)sys.modules["__prefect_loader__"]=module# Support implicit relative imports i.e. `from foo import bar`sys.path.insert(0,working_directory)sys.path.insert(0,parent_path)try:spec.loader.exec_module(module)exceptExceptionasexc:raiseScriptError(user_exc=exc,path=path)fromexcfinally:sys.modules.pop("__prefect_loader__")sys.path.remove(parent_path)sys.path.remove(working_directory)returnmodule
Run a python script and return all the global variables
Supports remote paths by copying to a local temporary file.
WARNING: The Python documentation does not recommend using runpy for this pattern.
Furthermore, any functions and classes defined by the executed code are not
guaranteed to work correctly after a runpy function has returned. If that
limitation is not acceptable for a given use case, importlib is likely to be a
more suitable choice than this module.
The function load_script_as_module uses importlib instead and should be used
instead for loading objects from scripts.
Parameters:
Name
Type
Description
Default
path
str
The path to the script to run
required
text
Union[str, bytes]
Optionally, the text of the script. Skips loading the contents if given.
defobjects_from_script(path:str,text:Union[str,bytes]=None)->Dict[str,Any]:""" Run a python script and return all the global variables Supports remote paths by copying to a local temporary file. WARNING: The Python documentation does not recommend using runpy for this pattern. > Furthermore, any functions and classes defined by the executed code are not > guaranteed to work correctly after a runpy function has returned. If that > limitation is not acceptable for a given use case, importlib is likely to be a > more suitable choice than this module. The function `load_script_as_module` uses importlib instead and should be used instead for loading objects from scripts. Args: path: The path to the script to run text: Optionally, the text of the script. Skips loading the contents if given. Returns: A dictionary mapping variable name to value Raises: ScriptError: if the script raises an exception during execution """defrun_script(run_path:str):# Cast to an absolute path before changing directories to ensure relative paths# are not brokenabs_run_path=os.path.abspath(run_path)withtmpchdir(run_path):try:returnrunpy.run_path(abs_run_path)exceptExceptionasexc:raiseScriptError(user_exc=exc,path=path)fromexciftext:withNamedTemporaryFile(mode="wt"ifisinstance(text,str)else"wb",prefix=f"run-{filename(path)}",suffix=".py",)astmpfile:tmpfile.write(text)tmpfile.flush()returnrun_script(tmpfile.name)else:ifnotis_local_path(path):# Remote paths need to be local to runwithfsspec.open(path)asf:contents=f.read()returnobjects_from_script(path,contents)else:returnrun_script(path)
Given an object, returns its fully-qualified name: a string that represents its
Python import path.
Parameters:
Name
Type
Description
Default
obj
Any
an importable Python object
required
Returns:
Name
Type
Description
str
str
the qualified name
Source code in src/prefect/utilities/importtools.py
20212223242526272829303132333435
defto_qualified_name(obj:Any)->str:""" Given an object, returns its fully-qualified name: a string that represents its Python import path. Args: obj (Any): an importable Python object Returns: str: the qualified name """ifsys.version_info<(3,10):# These attributes are only available in Python 3.10+ifisinstance(obj,(classmethod,staticmethod)):obj=obj.__func__returnobj.__module__+"."+obj.__qualname__