Sidor

Wednesday, October 2, 2024

Addon Scripting and Blender Extensions

As mentioned in the previous post on Blender Extensions and GPL, the DAZ Importer is now a Blender extension under Blender 4.2. It still works as a legacy addon in earlier Blender versions. This poses some challenges when using the addon in scripts. Here is an example.

import bpy
import import_daz

relpath = "/scenes/aiko-basic-wear.duf"
abspaths = import_daz.get_absolute_paths([relpath])
import_daz.set_selection(abspaths)
bpy.ops.daz.easy_import_daz(
   useExpressions = True,
   useJcms = True,
   clothesColor = (0,0,1,1.000),
   useTransferClothes = True,
   useMakePosable = True,
)
print("Loaded %s" % import_daz.get_selection())


This script loads a scene with Aiko dressed in Basic wear. The scene is located in the scenes directory under one of the DAZ root paths. The corresponding absolute path depends on the root paths specified in the global settings, and we use the import_daz.get_absolute_paths() function to retrieve it. Since a relative path may correspond to multiple absolute paths, this function returns a list.

Easy import is done with the bpy.ops.daz.easy_import_daz() operator, but we have to tell it which files to import first. This is done with the import_daz.set_selection() function, which should be called before any operator that acts on a list of strings.

The script above works fine in Blender 4.1 and earlier versions of Blender (some keyword argument may be different in very old addon versions), but in Blender 4.2 it causes an error:

ModuleNotFoundError: No module named 'import_daz'

The culprit is the line

import import_daz

which doesn't work because the import_daz module is not in the Python path anymore. To resolve this, we first notice that the entire DAZ Importer API is located in the import_daz.api submodule, which can be imported into the script with the line

from bl_ext.user_default.import_daz import api

Since we have imported the api module rather than the import_daz one, all function calls must change. E.g.,

abspaths = import_daz.get_absolute_paths([relpath])

is replaced by

abspaths = api.get_absolute_paths([relpath])


With these modifications, the full script becomes

import bpy
from bl_ext.user_default.import_daz import api

relpath = "/scenes/aiko-basic-wear.duf"
abspaths = api.get_absolute_paths([relpath])
api.set_selection(abspaths)
bpy.ops.daz.easy_import_daz(
   useExpressions = True,
   useJcms = True,
   clothesColor = (0,0,1,1.000),
   useTransferClothes = True,
   useMakePosable = True,
)
print("Loaded %s" % api.get_selection())

The new script works fine in Blender 4.2, but now we get an error when running the script in Blender 4.1.

ModuleNotFoundError: No module named 'bl_ext.user_default'; 'bl_ext' is not a package

To make the script work both in Blender 4.2 and earlier Blender versions, we can replace the code at the top with

try:
    from import_daz import api
except ModuleNotFoundError:
    from bl_ext.user_default.import_daz import api