Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2021-02-19 03:13:35 +0300
committerCampbell Barton <ideasman42@gmail.com>2021-02-19 03:23:30 +0300
commiteecb90d8d2ec68f4f3cb8b47ee9828dad5af60d6 (patch)
tree203ec739076df64f95c1a2f951f5e3846d87fe6e /release/scripts/modules/bpy
parent4604350eefabbfeeb97347bc3e6a996750de15aa (diff)
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.
Diffstat (limited to 'release/scripts/modules/bpy')
-rw-r--r--release/scripts/modules/bpy/utils/__init__.py33
1 files changed, 29 insertions, 4 deletions
diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py
index d984a6f54a4..2b19d23a367 100644
--- a/release/scripts/modules/bpy/utils/__init__.py
+++ b/release/scripts/modules/bpy/utils/__init__.py
@@ -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