RNA: path_resolve() doesn't deal with single-quoted keys #120140
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#120140
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
System Information
Operating system: Windows-10-10.0.19045-SP0 64 Bits
Graphics card: NVIDIA GeForce RTX 4070 SUPER/PCIe/SSE2 NVIDIA Corporation 4.6.0 NVIDIA 551.61
Blender Version
Broken: version: 4.1.0, branch: blender-v4.1-release, commit date: 2024-03-25 20:42, hash:
40a5e739e270
Worked: Don't think it ever did; 3.0 and 2.78 already had this problem, and I didn't bother going back further.
Short description of error
bpy.data.path_resolve('objects["Cube"]')
works,bpy.data.path_resolve("objects['Cube']")
does not:What makes this a true bug, rather than something simply unsupported, is that
repr(the_cube_object)
returns a path with single quotes. So Blender produces paths that are incompatible withpath_resolve()
.Exact steps for others to reproduce the error
bpy.data.path_resolve
and see the results.I believe by slightly changing
rna_path_token_in_brackets
andBLI_str_escape_find_quote
we can support path_resolve with single bracket.Might affect other places that uses
BLI_str_quoted_substr
, looks like escape characters don't play a big role there, so should be trivial...Making a PR
Note that single quotes were/are intentionally not supported, even if single quotes are supported there will be subtle differences between Blender's quoting and Python's repr.
To generate blender compatible quoting there is
bpy.utils.escape_identifier
&unescape_identifier
.Looking into this further and I think this may be more an issue of documentation needing to clarify the purpose of RNA data-paths.
RNA data-paths aren't the same as printing a Python object, but this probably isn't made clear anywhere in the API docs. I think it'd be best to have a section in the API reference detailing what data-paths are exactly, and how they are expected to be used.
While supporting single quotes in isolation can work, in introduces the following issues:
The expectation that data-paths are compatible with Python strings
This isn't the case, if simple quotes are supported developers are likely to use
repr()
to construct animation paths only to run into rare bugs where this fails. Python will escape certain characters in ways Blender wont, makingrepr()
fail to resolve.To show a concrete example: assigning the names
A_\x16_B
orA_\uEEEE_B
creates a name that wont resolve viapath_resolve
, I suspect there would be other similar cases, this is just two picked off hand.Complications with Stored Data-Paths (Animation Paths & Overrides)
Having a simple data-path allows us to consider a data-path a canonical reference to a property *.
Supporting both kinds of quotes means that Python scripts will be able to construct data-paths using either kind of quote and use them to setup key-frames, drivers & overrides.
While the paths will animate (from testing !120141), the logic to check if an RNA path is animated doesn't work.
The properties don't highlight as animated in the UI for example & Inserting a key-frame causes two F-curves that reference the same property. The UI & key-framing logic could be extended to normalize data-paths before comparison or resolve them & check the target matches - but this is reasonably involved for a check which we want to run on redraw.
It also complicates versioning - currently data-paths are constructed and replaced.
BKE_animsys_fix_rna_path_rename
would need to check on both single & double quoted paths, there are various other parts of the code which would need to be updatedupdate_mapping_node_fcurve_rna_path_callback
&version_liboverride_nla_strip_frame_start_end
for e.g.An alternative option to extending RNA data-paths could be to support
path_resolve()
having a Python compatible option which doesn't impact lower level RNA path resolution, so any valid Python data-path can work. This would end up being more like a secureeval(..)
.* exceptions to this exist: there are sometimes multiple RNA paths to access the same data, it's also the case for accessing data-paths via an index which would use a name when key-framing. In general though I think these kind of cases should be avoided where possible so the chance of script authors constructing incompatible animation paths is kept to a minimum.
Thanks Campbell for your detailed response.
I think this is a good, and necessary, idea.
A few things are getting mixed here.
There should be one canonical RNA path for a property: This I completely agree with. Having multiple RNA paths for a property makes so many things more cumbersome, it's not worth the effort of changing this. At least it's not what I wanted to suggest with this report ;-)
Not all Python expressions are valid RNA paths: This is quite strict, in the sense that it translates to "any string that looks like an RNA path that is not the canonical RNA path is invalid". I'm not sure how useful this strictness is for lookups by RNA path. As I said above, I can totally see some parts of Blender being restricted to the canonical path, but for me that doesn't immediately translate to such strictness for a function like
struct.path_resolve()
.My actual point is neither of the above though. I've done some more digging, and the confusion is caused by this: the result of
repr(rna_struct)
is a mixture of RNA path and Python expression. For a stringbpy.data.armatures['Armature.001'].bones["Bone"]
, thebpy.data.armatures['Armature.001']
part is generated as a Python expression, whereas thebones["Bone"]
part is an RNA path produced byrna_Bone_path()
.For the curious (and my own reference later on), this is implemented in
pyrna_struct_repr(BPy_StructRNA *self)
inbpy_rna.cc
. The use of%R
inPyUnicode_FromFormat("bpy.data.%s[%R].%s", ...)
is the culprit here. IMO this should use the same quoting rules as the rest of the RNA path handling code.When I interpret this strictly & literally, then it reduces the result of
repr(rna_struct)
to some human-readable string that is useless for anything else, as it is the concatenation of two incompatible strings.Much of that works fine though. It's only when you use
repr()
on the name itself, and then feed that topath_resolve()
, where things go wrong:Note that in the above, I've replaced the actual
\x16
codepoint with ⑯ for displayability in Gitea.I think this could even be the default behaviour for
path_resolve()
. To me,A.path_resolve(B)
succeeding does not mean thatB
is the canonical RNA path. To get that I'd like to userepr(A.path_resolve(B))
, except that doesn't return an RNA path at all. Andposebone.path_from_id()
excludes the owning object, making it useless for my actual purpose (using the bone's RNA path to get to its owner).To me, these are different functions:
If one of these is actually used in place of another (like using the fact that it resolves as an indication that the path is the canonical one), that seems like a deeper design mistake to me.