CollectionProperty как параметр оператора

·

Если вам надо передать в дефолтный оператор что-то из дефолтных типов, вы с высокой вероятностью столкнетесь с очень странной ошибкой:

Python
TypeError: Converting py args to operator properties:
WM_OT_obj_import.files expected a each sequence member to be a dict for an RNA collection, not OperatorFileListElement

tl;dr Вместо передачи коллекции объектов нужного нам класса (напр. CollectionProperty(type=OperatorFileListElement)), делаем словарь, в котором ключи соответствуют полям класса, и прямо так его передаём в оператор, который сам это всё соберёт.


Предыстория: мне понадобилось автоматизировать импорт большой кучи .OBJ файлов из разных папок. Вызывать bpy.ops.wm.obj_import() на каждый файл – сомнительная история, да и по скорости это заметно уступало импорту всех файлов в папке одним вызовом оператора.

Неожиданные проблемы начались при попытке передать список файлов files, который согласно документации должен быть коллекцией OperatorFileListElement.

Прицепить его можно «как обычно» к сцене:

Python
from bpy.props import CollectionProperty
from bpy.types import OperatorFileListElement

bpy.types.Scene.filelist = CollectionProperty(
    name="File Lists",
    type=OperatorFileListElement,
)

Вот только при попытке вызвать bpy.ops.wm.obj_import(directory=root, files=context.scene.filelist) вываливается та самая ошибка:

Python
TypeError: Converting py args to operator properties:
WM_OT_obj_import.files expected a each sequence member to be a dict for an RNA collection, not OperatorFileListElement

Решений есть две штуки:

  1. Для оператора в UI
  2. Для оператора без UI

Если у нас вызов дефолтного оператора производится без интерфейса, то нужно сделать словарь, в котором ключи повторяют имена полей нужного нам класса, в данном случае у OperatorFileListElement(PropertyGroup) это просто name, куда записывается имя нужного файла в directory.

Затем этот словарь мы напрямую передаём параметром в оператор, который «собирает» нужные объекты сам.

Python
filepath = bpy.data.filepath
search_path = os.path.dirname(filepath)
file_dicts = []

for root, dirs, files in os.walk(search_path):
    for file in files:
        file_dicts.append({'name': file})
    if len(file_dicts) > 0:
        bpy.ops.wm.obj_import(directory=root,
                              files=file_dicts)
    file_dicts.clear()

Видимо expected a each sequence member to be a dict for an RNA collection то и значит, но понять это сходу довольно сложно.

Comments

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *