Skip to main content
added 617 characters in body
Source Link
Gorgious
  • 31.8k
  • 2
  • 49
  • 106

Another solution which doesn't rely on knowing the collection items' type beforehand.

Get the property special dictionary construct by accessing the holder's (bpy_struct.id_data) custom properties (barely documented bl_rna.properties), and get the property by name using bpy_struct.path_from_id.

import bpy
from bpy.props import StringProperty, CollectionProperty

class MyCollectionProperty(bpy.types.PropertyGroup):
    name = StringProperty(default="")

bpy.utils.register_class(MyCollectionProperty)
bpy.types.Scene.my_collection_prop = CollectionProperty(type=MyCollectionProperty)

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    prop = collection_prop.id_data.bl_rna.properties.get(collection_prop.path_from_id())
    return type(prop.fixed_type) if prop is not None else None

assert MyCollectionProperty == get_class(bpy.data.scenes[0].my_collection_prop)

Note this will only work if the bpy.props.CollectionProperty is a direct member of a bpy.types.ID instance. In the case where a collection property is held in a property group you can use something like :

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    holder_path = ".".join(repr(collection_prop).split(".")[:-1])  # Get the path to the prop and remove the last element
    holder = eval(holder_path)
    prop_name = repr(collection_prop).split(".")[-1]
    return type(holder.bl_rna.properties.get(prop_name).fixed_type)

It's a bit more hacky but more extendable.

Another solution which doesn't rely on knowing the collection items' type beforehand.

Get the property special dictionary construct by accessing the holder's (bpy_struct.id_data) custom properties (barely documented bl_rna.properties), and get the property by name using bpy_struct.path_from_id.

import bpy
from bpy.props import StringProperty, CollectionProperty

class MyCollectionProperty(bpy.types.PropertyGroup):
    name = StringProperty(default="")

bpy.utils.register_class(MyCollectionProperty)
bpy.types.Scene.my_collection_prop = CollectionProperty(type=MyCollectionProperty)

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    prop = collection_prop.id_data.bl_rna.properties.get(collection_prop.path_from_id())
    return type(prop.fixed_type) if prop is not None else None

assert MyCollectionProperty == get_class(bpy.data.scenes[0].my_collection_prop)

Another solution which doesn't rely on knowing the collection items' type beforehand.

Get the property special dictionary construct by accessing the holder's (bpy_struct.id_data) custom properties (barely documented bl_rna.properties), and get the property by name using bpy_struct.path_from_id.

import bpy
from bpy.props import StringProperty, CollectionProperty

class MyCollectionProperty(bpy.types.PropertyGroup):
    name = StringProperty(default="")

bpy.utils.register_class(MyCollectionProperty)
bpy.types.Scene.my_collection_prop = CollectionProperty(type=MyCollectionProperty)

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    prop = collection_prop.id_data.bl_rna.properties.get(collection_prop.path_from_id())
    return type(prop.fixed_type) if prop is not None else None

assert MyCollectionProperty == get_class(bpy.data.scenes[0].my_collection_prop)

Note this will only work if the bpy.props.CollectionProperty is a direct member of a bpy.types.ID instance. In the case where a collection property is held in a property group you can use something like :

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    holder_path = ".".join(repr(collection_prop).split(".")[:-1])  # Get the path to the prop and remove the last element
    holder = eval(holder_path)
    prop_name = repr(collection_prop).split(".")[-1]
    return type(holder.bl_rna.properties.get(prop_name).fixed_type)

It's a bit more hacky but more extendable.

deleted 14 characters in body
Source Link
Gorgious
  • 31.8k
  • 2
  • 49
  • 106

Another solution which doesn't rely on knowing the collection items' type beforehand. Loop over all

Get the property's holderproperty special dictionary construct by accessing the holder's (bpy_struct.id_data) custom properties (barely documented bl_rna.properties), and return the type whenget the property by name matches using bpy_struct.path_from_id.

import bpy
from bpy.props import StringProperty, CollectionProperty

class MyCollectionProperty(bpy.types.PropertyGroup):
    name = StringProperty(default="")

bpy.utils.register_class(MyCollectionProperty)
bpy.types.Scene.my_collection_prop = CollectionProperty(type=MyCollectionProperty)

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    for key, valueprop in= collection_prop.id_data.bl_rna.properties.itemsget():
        if collection_prop.path_from_id() == key:)
     return type(prop.fixed_type) if prop is not None returnelse type(value.fixed_type)None

assert MyCollectionProperty == get_class(bpy.data.scenes[0].my_collection_prop)

Another solution which doesn't rely on knowing the collection items' type beforehand. Loop over all the property's holder (bpy_struct.id_data) custom properties, and return the type when the property name matches using bpy_struct.path_from_id.

import bpy
from bpy.props import StringProperty, CollectionProperty

class MyCollectionProperty(bpy.types.PropertyGroup):
    name = StringProperty(default="")

bpy.utils.register_class(MyCollectionProperty)
bpy.types.Scene.my_collection_prop = CollectionProperty(type=MyCollectionProperty)

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    for key, value in collection_prop.id_data.bl_rna.properties.items():
        if collection_prop.path_from_id() == key:
            return type(value.fixed_type)

assert MyCollectionProperty == get_class(bpy.data.scenes[0].my_collection_prop)

Another solution which doesn't rely on knowing the collection items' type beforehand.

Get the property special dictionary construct by accessing the holder's (bpy_struct.id_data) custom properties (barely documented bl_rna.properties), and get the property by name using bpy_struct.path_from_id.

import bpy
from bpy.props import StringProperty, CollectionProperty

class MyCollectionProperty(bpy.types.PropertyGroup):
    name = StringProperty(default="")

bpy.utils.register_class(MyCollectionProperty)
bpy.types.Scene.my_collection_prop = CollectionProperty(type=MyCollectionProperty)

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    prop = collection_prop.id_data.bl_rna.properties.get(collection_prop.path_from_id())
    return type(prop.fixed_type) if prop is not None else None

assert MyCollectionProperty == get_class(bpy.data.scenes[0].my_collection_prop)
Source Link
Gorgious
  • 31.8k
  • 2
  • 49
  • 106

Another solution which doesn't rely on knowing the collection items' type beforehand. Loop over all the property's holder (bpy_struct.id_data) custom properties, and return the type when the property name matches using bpy_struct.path_from_id.

import bpy
from bpy.props import StringProperty, CollectionProperty

class MyCollectionProperty(bpy.types.PropertyGroup):
    name = StringProperty(default="")

bpy.utils.register_class(MyCollectionProperty)
bpy.types.Scene.my_collection_prop = CollectionProperty(type=MyCollectionProperty)

def get_class(collection_prop: bpy.types.CollectionProperty) -> type:
    for key, value in collection_prop.id_data.bl_rna.properties.items():
        if collection_prop.path_from_id() == key:
            return type(value.fixed_type)

assert MyCollectionProperty == get_class(bpy.data.scenes[0].my_collection_prop)