11
$\begingroup$

Now that we need to use field for property declarations in Blender 2.8. I was wondering how this can be done when creating class dynamically using type() like so:

type('TestPropGrp', (bpy.types.PropertyGroup,), {‘MyProp’:StringProperty(default=‘MyStr’)}) 

=> this would work in Blender 2.8 but will throw a 'make field' warning.

Any idea how to declare field when using type() ?

Thank you !

edit (this is actually wrong - see answer): Of course one way to do it is to write this in 2 lines:

clss = type('TestPropGrp', (bpy.types.PropertyGroup,), {})

clss.myProp : StringProperty(default=‘MyStr’)

but I was wondering if there could be a more compact solution ?

$\endgroup$
0

2 Answers 2

12
+50
$\begingroup$

The annotations for an object (which can be a class or a function as well) are stored in its __annotations__ property, as defined by PEP 526 and introduced in Python 3.6. This gives rise to the following solution:

The following approach works as I suspect you're looking for:

>>> clss = type('TestPropGrp2', (bpy.types.PropertyGroup,), { ... '__annotations__': {'myProp': (StringProperty, {'default': 'MyStr'})} ... }) >>> print(clss.__annotations__) {'myProp': (<built-in function StringProperty>, {'default': 'MyStr'})} 

This also allows you to see that your proposed "one way to do it" approach doesn't actually work as intended:

>>> clss = type('TestPropGrp', (bpy.types.PropertyGroup,), {}) >>> clss.myProp : StringProperty(default='MyStr') >>> print(clss.__annotations__) Traceback (most recent call last): File "<blender_console>", line 1, in <module> AttributeError: type object 'TestPropGrp' has no attribute '__annotations__' 
$\endgroup$
3
  • $\begingroup$ Thx Sybren! I’m still confuse with the use a field property but that will help. I need to test but There is si till some blurred case like what would be the init value if you declare: myProp: bpy.props.StringProperty(default=‘MyString’) = ‘myString2’. $\endgroup$ Commented Sep 18, 2018 at 11:48
  • $\begingroup$ You wouldn't pass default='MyString', I think. Just write clear, unambiguous code ;-) $\endgroup$ Commented Sep 20, 2018 at 14:14
  • $\begingroup$ Well that is the way we were passing a default value for StringProperty before so it means that now with field property this doesn’t make any sense. BTW, This notation would end up with myProp having a value of ´myString’. $\endgroup$ Commented Sep 20, 2018 at 17:07
6
$\begingroup$

I’ll extend Sybren's answer above with a warning, after some bug just found in our @orientation_helper() IO class decorator today (see https://developer.blender.org/T58772 ). It does not directly affect your example, but it could in some slightly different dynamic class generation cases.

Do ensure you have an __annotations__ dict defined in the class you want to add fields to! Otherwise:

  • If one of your parent classes defines it, you will actually add the field to that parent's __annotations__ dict, effectively adding that field to all the children classes as well, and not only the one you wanted to.
  • If there is no __annotations__ defined anywhere in parent's hierarchy, you'll just get an error (which is much simpler to debug than the first case).

Bug linked above leaded to all IO add-ons using ImportHelper as parent of their Import operator to display the Up/Front axes selectors, even though they would not need them. We had to switch from that (simplified code):

def orientation_helper(axis_forward='Y', axis_up='Z'): def wrapper(cls): cls.__annotations__['axis_forward'] = StringProperty() 

…to that:

def orientation_helper(axis_forward='Y', axis_up='Z'): def wrapper(cls): # Without that, we may end up adding those fields to some **parent** class' __annotations__ property # (like the ImportHelper or ExportHelper ones)! See T58772. if "__annotations__" not in cls.__dict__: setattr(cls, "__annotations__", {}) cls.__annotations__['axis_forward'] = StringProperty() 
$\endgroup$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.