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 <campbell@blender.org>2022-04-06 04:42:46 +0300
committerCampbell Barton <campbell@blender.org>2022-04-06 04:48:51 +0300
commit7bb8eeb3a871eb1e72ee129f8ff441f2752b37be (patch)
tree8b94749024d4ed1ffa8d298075ad98dc186301a4
parent5d31252c762b35a5af3d668f45dccf5bb397627e (diff)
PyAPI: Add Context.path_resolve wrapper that supports context members
This avoids script authors using `eval("context.%s" % data_path)` to access paths starting from the context, which isn't good practice especially if the data_path isn't trusted. Now it's possible to resplve paths such as: context.path_resolve('active_object.modifiers[0].name')
-rw-r--r--release/scripts/modules/bpy_types.py53
1 files changed, 53 insertions, 0 deletions
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index e0e20d0f8c9..45fd6d29dfa 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -8,12 +8,65 @@ StructRNA = bpy_types.bpy_struct
StructMetaPropGroup = bpy_types.bpy_struct_meta_idprop
# StructRNA = bpy_types.Struct
+# Private dummy object use for comparison only.
+_sentinal = object()
+
# Note that methods extended in C are defined in: 'bpy_rna_types_capi.c'
class Context(StructRNA):
__slots__ = ()
+ def path_resolve(self, path, coerce=True):
+ """
+ Returns the property from the path, raise an exception when not found.
+
+ :arg path: patch which this property resolves.
+ :type path: string
+ :arg coerce: optional argument, when True, the property will be converted into its Python representation.
+ :type coerce: boolean
+ """
+ # This is a convenience wrapper around `StructRNA.path_resolve` which doesn't support accessing context members.
+ # Without this wrapper many users were writing `exec("context.%s" % data_path)` which is a security
+ # concern if the `data_path` comes from an unknown source.
+ # This function performs the initial lookup, after that the regular `path_resolve` function is used.
+
+ # Extract the initial attribute into `(attr, path_rest)`.
+ sep = len(path)
+ div = ""
+ for div_test in (".", "["):
+ sep_test = path.find(div_test, 0, sep)
+ if sep_test != -1 and sep_test < sep:
+ sep = sep_test
+ div = div_test
+ if div:
+ attr = path[:sep]
+ if div == ".":
+ sep += 1
+ path_rest = path[sep:]
+ else:
+ attr = path
+ path_rest = ""
+
+ # Retrieve the value for `attr`.
+ # Match the value error exception with that of "path_resolve"
+ # to simplify exception handling for the caller.
+ value = getattr(self, attr, _sentinal)
+ if value is _sentinal:
+ raise ValueError("Path could not be resolved: %r" % attr)
+
+ if value is None:
+ return value
+
+ # Resolve the rest of the path if necessary.
+ if path_rest:
+ path_resolve_fn = getattr(value, "path_resolve", None)
+ if path_resolve_fn is None:
+ raise ValueError("Path %s resolves to a non RNA value" % attr)
+ return path_resolve_fn(path_rest, coerce)
+
+ return value
+
def copy(self):
from types import BuiltinMethodType
new_context = {}