EnumProperty items argument id?

Hello,
I’m setting an EnumProperty’s items argument via a callback to a function. In the api docs (http://www.blender.org/api/blender_python_api_2_75_3/bpy.props.html?highlight=enumproperty#bpy.props.EnumProperty) it says:

  • items (sequence of string tuples or a function) – sequence of enum items formatted: [(identifier, name, description, icon, number), …] where the identifier is used for python access and other values are used for the interface. The three first elements of the tuples are mandatory. The forth one is either the (unique!) number id of the item or, if followed by a fith element (which must be the numid), an icon string identifier or integer icon value (e.g. returned by icon()…). Note the item is optional. For dynamic values a callback can be passed which returns a list in the same format as the static list. This function must take 2 arguments (self, context), context may be None. WARNING: There is a known bug with using a callback, Python must keep a reference to the strings returned or Blender will crash.

To use an icon I need to set an unique number id as well, for what can I use this number id? Why can’t I use an icon without also using an id? Is this id simply for blenders internal use or what?

It is required internally indeed. If you supply the same number as ID multiple times, it will cause problems. You won’t be able to set the enum property to the duplicate entries, it will always change to the first occurrence of the id number.

>>> bpy.types.Scene.p=bpy.props.EnumProperty(items=(('1','one','','X', 0),('2','two','','TRIA_UP', 0)))
>>> C.scene.p = '2'
>>> C.scene.p
'1'

The reverse it possible however:

bpy.types.Scene.p=bpy.props.EnumProperty(items=(('1','one','','X', 0),('1','two','','TRIA_UP', 1)))

note that ‘1’ is used as string key twice, but the IDs are different. Go to Scene tab > Custom Properties panel and select either of the items. You can select both. You can’t distinguish them with Python like this however:

>>> C.scene.p
‘1’

It will print ‘1’ no matter which of the two items is selected.

If you access it as ID property however, the ID will be returned and the selected item can therefore be determined:

>>> C.scene[“p”]
0 # item one is selected, would otherwise be 1

Note that there will not be a scene[“p”] initially until something is assigned to scene.p or scene[“p”] the first time (UI or script).

Okey, thanks! But I also wonder why I need to set an ID only if I use an icon? Even if I don’t use an icon, python will still need to ID these items to separate them right? Why can’t they get IDs automatically if I use icons?

That’s not true, you must specify an ID if there are duplicate string keys, even if you don’t use icons. It might be required to pass IDs if you want to use icons, despite unique string keys, because the function signature would be ambigious:

(key, label, descr, id) – four parameters means the 4th is ID
(key, label, descr, id, icon) – five paramters means the 4th is icon name, 5th ID
(key, label, descr, icon) <-- how would it know this isn’t an ID?

You could theoretically do a type check (int means ID, str means icon name), but that could only be done dynamically. It would take some effort to make this work, and it would be slower. I guess no one bothered to support this, since it’s not a big deal to also pass a number…

Oh, you’re right! Thank you for your help!