[Bf-blender-cvs] [7bb8eeb3a87] master: PyAPI: Add Context.path_resolve wrapper that supports context members
Campbell Barton
noreply at git.blender.org
Wed Apr 6 10:03:39 CEST 2022
Commit: 7bb8eeb3a871eb1e72ee129f8ff441f2752b37be
Author: Campbell Barton
Date: Wed Apr 6 11:42:46 2022 +1000
Branches: master
https://developer.blender.org/rB7bb8eeb3a871eb1e72ee129f8ff441f2752b37be
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')
===================================================================
M release/scripts/modules/bpy_types.py
===================================================================
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 = {}
More information about the Bf-blender-cvs
mailing list