PyAPI: bpy.utils.execfile temporarily overrides the __main__ module
This is needed to support Python 3.10's `typing.get_type_hints`, to access the name-space used when creating the class. Also added a docstring for execfile.
This commit is contained in:
parent
4604350eef
commit
eecb90d8d2
@ -82,14 +82,39 @@ _is_factory_startup = _bpy.app.factory_startup
|
||||
|
||||
|
||||
def execfile(filepath, mod=None):
|
||||
# module name isn't used or added to 'sys.modules'.
|
||||
# passing in 'mod' allows re-execution without having to reload.
|
||||
"""
|
||||
Execute a file path as a Python script.
|
||||
|
||||
:arg filepath: Path of the script to execute.
|
||||
:type filepath: string
|
||||
:arg mod: Optional cached module, the result of a previous execution.
|
||||
:type mod: Module or None
|
||||
:return: The module which can be passed back in as ``mod``.
|
||||
:rtype: ModuleType
|
||||
"""
|
||||
|
||||
import importlib.util
|
||||
mod_spec = importlib.util.spec_from_file_location("__main__", filepath)
|
||||
mod_name = "__main__"
|
||||
mod_spec = importlib.util.spec_from_file_location(mod_name, filepath)
|
||||
if mod is None:
|
||||
mod = importlib.util.module_from_spec(mod_spec)
|
||||
mod_spec.loader.exec_module(mod)
|
||||
|
||||
# While the module name is not added to `sys.modules`, it's important to temporarily
|
||||
# include this so statements such as `sys.modules[cls.__module__].__dict__` behave as expected.
|
||||
# See: https://bugs.python.org/issue9499 for details.
|
||||
modules = _sys.modules
|
||||
mod_orig = modules.get(mod_name, None)
|
||||
modules[mod_name] = mod
|
||||
|
||||
# No error supression, just ensure `sys.modules[mod_name]` is properly restored in the case of an error.
|
||||
try:
|
||||
mod_spec.loader.exec_module(mod)
|
||||
finally:
|
||||
if mod_orig is None:
|
||||
modules.pop(mod_name, None)
|
||||
else:
|
||||
modules[mod_name] = mod_orig
|
||||
|
||||
return mod
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user