GSoC 2025 - Week 6
I made the following progress this week:
- PR #891 (merged)
- Updated the underlying datastore for annotations to use Blender properties instead of Geometry Nodes
- Added tests to handle exceptions as well - based on
Codecov
report
- PR #900 (merged)
- Added custom validation support for Annotation classes
- PR #901 (merged)
- Added the base annotations draw handler code
- Basic 3D and 2D text drawing with working atom info annotation for Trajectories
- PR #903 (open)
- Added basic line drawing support for annotations
- Working center-of-mass and distance between center-of-masses annotation for Trajectories
Here is a video that shows the annotations progress so far:
Here are some learning from this week:
- Dynamic properties are a great way to support extensibility in Blender
- A
CollectionProperty
with a dynamicPropertyGroup
can be assigned to standard types (likebpy.types.Object
) at runtime. This is the key that allows extensibility. Blender converts these to ID properties when the corresponding type classes are not registered. Once the type classes are registered they become API defined properties- The property path has to be at the top level and not nested under another property. For example,
bpy.types.Object.mn_annotations
works, butbpy.types.Object.mn.annotations
doesn’t. The later leads to aAttributeError: '_PropertyDeferred' object has no attribute '...'
error
- The property path has to be at the top level and not nested under another property. For example,
.bl_rna.properties
of aPropertyGroup
can be used to iterate all the properties within aPropertyGroup
. The property name is available under theidentifier
attribute of the iterated item. Thetype
attribute specifies the property type (likePOINTER
etc)- Changing Blender properties through API will need the viewport to be tagged for redraw to show updated values immediately in Blender’s GUI
with pytest.raises
can be used to test exceptions in pytest tests- A lambda function can be used to pass the actual property name within a property group that caused the update in the update callback
- Care should be taken when using lambda functions in a loop - a closure is needed to ensure that correct values are passed - this can be done using defaults, a custom function etc
bpy.types.Operator.__subclasses__()
andbpy.types.PropertyGroup.__subclasses__()
can be used to verify whether temporary operators and property groups are being unregistered and garbage collected.sys.getrefcount
can be used on a class to get the reference counts
Next week, I plan to continue working on annotations - more shapes, other trajectory annotations and rendering support for annotations.
This post is licensed under CC BY 4.0 by the author.