2
$\begingroup$

I want to get the full path of a specific property (such as bone_target in the driver panel or parent of an edit bone) but it is grayed out and unusable, is there another way to get the data path?

Calling the operator from a grayed out context only returned Operator bpy.ops.ui.copy_data_path_button.poll() failed, context is incorrect.

Also, I tried context.property but could only get (bpy.data.objects['ObjectName'], 'bone_target', -1).

import bpy

class OperatorSomething(bpy.types.Operator):
    bl_idname = "object.operator_something"
    bl_label = "Operator Something"
    bl_options = {'REGISTER', 'UNDO'}

    def invoke(self, context, event):
        # I want the full path of the data here, just like bpy.ops.ui.copy_data_path_button()
        return {'FINISHED'}

def draw_menu(self, context):
    layout = self.layout
    layout.operator(OperatorSomething.bl_idname,
                    text="")
    

def register():
    bpy.utils.register_class(OperatorSomething)
    bpy.types.UI_MT_button_context_menu.append(draw_menu)

Drivers panel

$\endgroup$

1 Answer 1

1
$\begingroup$
# version blender 4.2

import bpy
from bpy.utils import escape_identifier

blendData_to_class = {
    "actions":          "Action",
    "armatures":        "Armature",
    "brushes":          "Brush",
    "cache_files":      "CacheFile",
    "cameras":          "Camera",
    "collections":      "Collection",
    "curves":           "Curve",
    "fonts":            "VectorFont",
    "grease_pencils":   "GreasePencil",
    "hair_curves":      "Curves",
    "images":           "Image",
    "lattices":         "Lattice",
    "libraries":        "Library",
    "lightprobes":      "LightProbe",
    "lights":           "Light",
    "linestyles":       "FreestyleLineStyle",
    "masks":            "Mask",
    "materials":        "Material",
    "meshes":           "Mesh",
    "metaballs":        "MetaBall",
    "movieclips":       "MovieClip",
    "node_groups":      "NodeTree",
    "objects":          "Object",
    "paint_curves":     "PaintCurve",
    "palettes":         "Palette",
    "particles":        "ParticleSettings",
    "pointclouds":      "PointCloud",
    "scenes":           "Scene",
    "screens":          "Screen",
    "shape_keys":       "Key",
    "sounds":           "Sound",
    "speakers":         "Speaker",
    "texts":            "Text",
    "textures":         "Texture",
    "volumes":          "Volume",
    "window_managers":  "WindowManager",
    "workspaces":       "WorkSpace",
    "worlds":           "World"}
class_to_blendData = {v: k for k, v in blendData_to_class.items()}

def get_ob_dp(obj):
    try:
        if hasattr(obj, "library") and obj.library:
            return f'bpy.data.{class_to_blendData[obj.rna_type.identifier]}["{escape_identifier(obj.name)}", "{escape_identifier(obj.library.filepath)}"]'
        else:
            return f'bpy.data.{class_to_blendData[obj.rna_type.identifier]}["{escape_identifier(obj.name)}"]'
    except:
        return ""

def get_full_dp(base_object, attrs):
    dp = get_ob_dp(base_object)
    if dp:
        if not attrs:
            return dp
        if attrs.startswith('["'):
            return f'{dp}{attrs}'
        return f'{dp}.{attrs}'
    return ""

Get bone datapath

ob = bpy.data.armatures[0]
bone = ob.bones[0]
dp = get_full_dp(ob, f'bones["{escape_identifier(bone.name)}"].bbone_segments')
print(dp)

# >>>> bpy.data.armatures["Armature"].bones["Bone"].bbone_segments

Custom properties

ob = bpy.context.object
dp = get_full_dp(ob, '["prop"]')
print(dp)

# >>>> bpy.data.objects["Armature"]["prop"]

Linked Data-block

ob = bpy.context.object
dp = get_full_dp(ob, "")
print(dp)

# >>>> bpy.data.objects["Cube", "D:\\OneDrive\\Blender\\test.blend"]

escape_identifier

s = escape_identifier('\n"abc中"')
print(s)

# >>>> \n\"abc中\"


Tips and hints

Avoid using single quotes in blender datapath

# Wrong way:
import bpy

ob = bpy.context.object
dp = "modifiers['Boolean'].show_render"
fc = ob.animation_data.action.fcurves.find(dp)

print(fc) # It get None when the datapath has keyframes

# Correct Way:
dp = 'modifiers["Boolean"].show_render'
# and don't forget to check if animation_data exists and is None

Get All Object Keys

1

# Wrong way:
import bpy

kys = bpy.data.objects.keys()
print(kys)

# >>>> ['Cube', 'Cube']

# Correct way:
def get_key(ob):
    if hasattr(ob, "library") and ob.library:
        return ob.name, ob.library.filepath
    return ob.name

kys = [get_key(ob) for ob in bpy.data.objects]
print(kys)

# >>>> ['Cube', ('Cube', 'D:\\OneDrive\\test.blend')]
$\endgroup$
4
  • $\begingroup$ Hello, isn't get_ob_dp(obj) the same as repr(obj) ? $\endgroup$
    – Gorgious
    Commented Sep 5 at 11:11
  • $\begingroup$ @Gorgious No, repr is wrong on linked object. $\endgroup$
    – X Y
    Commented Sep 5 at 14:03
  • $\begingroup$ and repr is usually wrong because it displays single quotes instead of double quotes. $\endgroup$
    – X Y
    Commented Sep 5 at 14:29
  • $\begingroup$ Ok thank you for the explanation. I'm not well versed in animation shenanigans so this is helpful. Cheers $\endgroup$
    – Gorgious
    Commented Sep 5 at 19:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .