From 01e8af3348fac2babe3b5218dbe4ecdaa0e1eace Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 12 Nov 2022 23:54:17 +0200 Subject: Rigify: annotate and fix warnings in basic rig components. Introduce a method to annotate types and names of entries in the `bones` container of rig components and apply it, and other type annotations, to a number of not very complex rig classes. - Introduce BaseRigMixin as a typed base class for mixins intended for use in rig classes (using BaseRig as a parent causes issues). - Introduce TypedBoneDict that does not suppress the unknown attribute analysis in PyCharm, and use it in a system of subclasses to annotate the bones in various rigs. BaseBoneDict is necessary because the annotation affects all subclasses, so TypedBoneDict cannot inherit from BoneDict with the annotation. - Add or adjust other type annotations of rig methods and utilities. - Fix other warnings, e.g. undeclared attributes, excessively long lines, whitespace style issues and typos. --- rigify/rigs/basic/copy_chain.py | 14 +++++-- rigify/rigs/basic/pivot.py | 80 ++++++++++++++++++++----------------- rigify/rigs/basic/raw_copy.py | 88 ++++++++++++++++++++++------------------- rigify/rigs/basic/super_copy.py | 61 ++++++++++++++-------------- 4 files changed, 132 insertions(+), 111 deletions(-) (limited to 'rigify/rigs/basic') diff --git a/rigify/rigs/basic/copy_chain.py b/rigify/rigs/basic/copy_chain.py index cf77a834..3dbf79d4 100644 --- a/rigify/rigs/basic/copy_chain.py +++ b/rigify/rigs/basic/copy_chain.py @@ -11,6 +11,10 @@ class Rig(SimpleChainRig): and constrain it. This is a control and deformation rig. """ + + make_controls: bool + make_deforms: bool + def initialize(self): super().initialize() @@ -72,15 +76,17 @@ class Rig(SimpleChainRig): # Parameter UI @classmethod - def add_parameters(self, params): + def add_parameters(cls, params): """ Add the parameters of this rig type to the RigifyParameters PropertyGroup """ - params.make_controls = bpy.props.BoolProperty(name="Controls", default=True, description="Create control bones for the copy") - params.make_deforms = bpy.props.BoolProperty(name="Deform", default=True, description="Create deform bones for the copy") + params.make_controls = bpy.props.BoolProperty( + name="Controls", default=True, description="Create control bones for the copy") + params.make_deforms = bpy.props.BoolProperty( + name="Deform", default=True, description="Create deform bones for the copy") @classmethod - def parameters_ui(self, layout, params): + def parameters_ui(cls, layout, params): """ Create the ui for the rig parameters. """ r = layout.row() diff --git a/rigify/rigs/basic/pivot.py b/rigify/rigs/basic/pivot.py index a129e1e8..6812cde5 100644 --- a/rigify/rigs/basic/pivot.py +++ b/rigify/rigs/basic/pivot.py @@ -13,15 +13,27 @@ from ...utils.switch_parent import SwitchParentBuilder class Rig(BaseRig): """ A rig providing a rotation pivot control that can be moved. """ - def find_org_bones(self, pose_bone): - return pose_bone.name + class CtrlBones(BaseRig.CtrlBones): + master: str + pivot: str + + class MchBones(BaseRig.MchBones): + pass + + bones: BaseRig.ToplevelBones[str, CtrlBones, MchBones, str] + + make_control: bool + make_pivot: bool + make_deform: bool + + def find_org_bones(self, pose_bone) -> str: + return pose_bone.name def initialize(self): self.make_control = self.params.make_extra_control self.make_pivot = self.params.make_control or not self.make_control - self.make_deform = self.params.make_extra_deform - + self.make_deform = self.params.make_extra_deform def generate_bones(self): org = self.bones.org @@ -44,8 +56,7 @@ class Rig(BaseRig): if self.make_deform: self.bones.deform = self.copy_bone(org, make_derived_name(org, 'def'), bbone=True) - - def build_parent_switch(self, master_name): + def build_parent_switch(self, master_name: str): pbuilder = SwitchParentBuilder(self.generator) org_parent = self.get_bone_parent(self.bones.org) @@ -68,7 +79,7 @@ class Rig(BaseRig): tags.discard('') return tags - def register_parent(self, master_name, tags): + def register_parent(self, master_name: str, tags: set[str]): pbuilder = SwitchParentBuilder(self.generator) inject = self.rigify_parent if 'injected' in tags else None @@ -78,7 +89,6 @@ class Rig(BaseRig): inject_into=inject, tags=tags ) - def parent_bones(self): ctrl = self.bones.ctrl @@ -94,7 +104,6 @@ class Rig(BaseRig): if self.make_deform: self.set_bone_parent(self.bones.deform, self.bones.org, use_connect=False) - def configure_bones(self): org = self.bones.org ctrl = self.bones.ctrl @@ -102,7 +111,6 @@ class Rig(BaseRig): self.copy_bone_properties(org, main_ctl, ui_controls=True) - def rig_bones(self): if self.make_pivot: self.make_constraint( @@ -110,7 +118,6 @@ class Rig(BaseRig): space='LOCAL', invert_xyz=(True,)*3 ) - def generate_widgets(self): if self.make_pivot: create_pivot_widget(self.obj, self.bones.ctrl.pivot, square=True, axis_size=2.0) @@ -118,56 +125,55 @@ class Rig(BaseRig): if self.make_control: set_bone_widget_transform(self.obj, self.bones.ctrl.master, self.bones.org) - create_registered_widget(self.obj, self.bones.ctrl.master, self.params.pivot_master_widget_type or 'cube') - + create_registered_widget(self.obj, self.bones.ctrl.master, + self.params.pivot_master_widget_type or 'cube') @classmethod - def add_parameters(self, params): + def add_parameters(cls, params): params.make_control = bpy.props.BoolProperty( - name = "Control", - default = True, - description = "Create a control bone for the copy" + name="Control", + default=True, + description="Create a control bone for the copy" ) params.pivot_master_widget_type = bpy.props.StringProperty( - name = "Widget Type", - default = 'cube', - description = "Choose the type of the widget to create" + name="Widget Type", + default='cube', + description="Choose the type of the widget to create" ) params.make_parent_switch = bpy.props.BoolProperty( - name = "Switchable Parent", - default = False, - description = "Allow switching the parent of the master control" + name="Switchable Parent", + default=False, + description="Allow switching the parent of the master control" ) params.register_parent = bpy.props.BoolProperty( - name = "Register Parent", - default = False, - description = "Register the control as a switchable parent candidate" + name="Register Parent", + default=False, + description="Register the control as a switchable parent candidate" ) params.register_parent_tags = bpy.props.StringProperty( - name = "Parent Tags", - default = "", - description = "Comma-separated tags to use for the registered parent" + name="Parent Tags", + default="", + description="Comma-separated tags to use for the registered parent" ) params.make_extra_control = bpy.props.BoolProperty( - name = "Extra Control", - default = False, - description = "Create an optional control" + name="Extra Control", + default=False, + description="Create an optional control" ) params.make_extra_deform = bpy.props.BoolProperty( - name = "Extra Deform", - default = False, - description = "Create an optional deform bone" + name="Extra Deform", + default=False, + description="Create an optional deform bone" ) - @classmethod - def parameters_ui(self, layout, params): + def parameters_ui(cls, layout, params): r = layout.row() r.prop(params, "make_extra_control", text="Master Control") diff --git a/rigify/rigs/basic/raw_copy.py b/rigify/rigs/basic/raw_copy.py index 6a6153a3..f22f7533 100644 --- a/rigify/rigs/basic/raw_copy.py +++ b/rigify/rigs/basic/raw_copy.py @@ -2,15 +2,17 @@ import bpy -from ...utils.naming import strip_org, strip_prefix, choose_derived_bone, is_control_bone +from bpy.types import Constraint, ArmatureConstraint, UILayout + +from ...utils.naming import choose_derived_bone, is_control_bone from ...utils.mechanism import copy_custom_properties_with_ui, move_all_constraints from ...utils.widgets import layout_widget_dropdown, create_registered_widget -from ...base_rig import BaseRig -from ...base_generate import SubstitutionRig +from ...base_rig import BaseRig, BaseRigMixin from itertools import repeat + ''' Due to T80764, bone name handling for 'limbs.raw_copy' was hard-coded in generate.py @@ -25,18 +27,18 @@ class Rig(SubstitutionRig): return [ self.instantiate_rig(InstanceRig, new_name) ] ''' -class RelinkConstraintsMixin: + +class RelinkConstraintsMixin(BaseRigMixin): """ Utilities for constraint relinking. """ - def relink_bone_constraints(self, bone_name): + def relink_bone_constraints(self, bone_name: str): if self.params.relink_constraints: for con in self.get_bone(bone_name).constraints: self.relink_single_constraint(con) - relink_unmarked_constraints = False - def relink_single_constraint(self, con): + def relink_single_constraint(self, con: Constraint): if self.params.relink_constraints: parts = con.name.split('@') @@ -45,13 +47,11 @@ class RelinkConstraintsMixin: elif self.relink_unmarked_constraints: self.relink_constraint(con, ['']) - - def relink_move_constraints(self, from_bone, to_bone, *, prefix=''): + def relink_move_constraints(self, from_bone: str, to_bone: str, *, prefix=''): if self.params.relink_constraints: move_all_constraints(self.obj, from_bone, to_bone, prefix=prefix) - - def relink_bone_parent(self, bone_name): + def relink_bone_parent(self, bone_name: str): if self.params.relink_constraints: self.generator.disable_auto_parent(bone_name) @@ -62,13 +62,13 @@ class RelinkConstraintsMixin: self.set_bone_parent(bone_name, new_parent) return new_parent - - def relink_constraint(self, con, specs): - if con.type == 'ARMATURE': + def relink_constraint(self, con: Constraint, specs: list[str]): + if isinstance(con, ArmatureConstraint): if len(specs) == 1: specs = repeat(specs[0]) elif len(specs) != len(con.targets): - self.raise_error("Constraint {} actually has {} targets", con.name, len(con.targets)) + self.raise_error("Constraint {} actually has {} targets", + con.name, len(con.targets)) for tgt, spec in zip(con.targets, specs): if tgt.target == self.obj: @@ -76,44 +76,49 @@ class RelinkConstraintsMixin: elif hasattr(con, 'subtarget'): if len(specs) > 1: - self.raise_error("Only the Armature constraint can have multiple '@' targets: {}", con.name) + self.raise_error("Only the Armature constraint can have multiple '@' targets: {}", + con.name) + # noinspection PyUnresolvedReferences if con.target == self.obj: con.subtarget = self.find_relink_target(specs[0], con.subtarget) - - def find_relink_target(self, spec, old_target): + def find_relink_target(self, spec: str, old_target: str): if spec == '': return old_target elif spec in {'CTRL', 'DEF', 'MCH'}: result = choose_derived_bone(self.generator, old_target, spec.lower()) if not result: - result = choose_derived_bone(self.generator, old_target, spec.lower(), by_owner=False) + result = choose_derived_bone(self.generator, old_target, + spec.lower(), by_owner=False) if not result: - self.raise_error("Cannot find derived {} bone of bone '{}' for relinking", spec, old_target) + self.raise_error("Cannot find derived {} bone of bone '{}' for relinking", + spec, old_target) return result else: if spec not in self.obj.pose.bones: self.raise_error("Cannot find bone '{}' for relinking", spec) return spec - @classmethod - def add_relink_constraints_params(self, params): + def add_relink_constraints_params(cls, params): params.relink_constraints = bpy.props.BoolProperty( - name = "Relink Constraints", - default = False, - description = "For constraints with names formed like 'base@bonename', use the part after '@' as the new subtarget after all bones are created. Use '@CTRL', '@DEF' or '@MCH' to simply replace the prefix" + name="Relink Constraints", + default=False, + description="For constraints with names formed like 'base@bonename', use the part " + "after '@' as the new subtarget after all bones are created. Use '@CTRL', " + "'@DEF' or '@MCH' to simply replace the prefix" ) params.parent_bone = bpy.props.StringProperty( - name = "Parent", - default = "", - description = "Replace the parent with a different bone after all bones are created. Using simply CTRL, DEF or MCH will replace the prefix instead" + name="Parent", + default="", + description="Replace the parent with a different bone after all bones are created. " + "Using simply CTRL, DEF or MCH will replace the prefix instead" ) @classmethod - def add_relink_constraints_ui(self, layout, params): + def add_relink_constraints_ui(cls, layout: UILayout, params): r = layout.row() r.prop(params, "relink_constraints") @@ -125,7 +130,11 @@ class RelinkConstraintsMixin: class Rig(BaseRig, RelinkConstraintsMixin): - def find_org_bones(self, pose_bone): + bones: BaseRig.ToplevelBones[str, BaseRig.CtrlBones, BaseRig.MchBones, str] + + relink: bool + + def find_org_bones(self, pose_bone) -> str: return pose_bone.name def initialize(self): @@ -149,23 +158,22 @@ class Rig(BaseRig, RelinkConstraintsMixin): create_registered_widget(self.obj, org, widget) @classmethod - def add_parameters(self, params): - self.add_relink_constraints_params(params) + def add_parameters(cls, params): + cls.add_relink_constraints_params(params) params.optional_widget_type = bpy.props.StringProperty( - name = "Widget Type", - default = '', - description = "Choose the type of the widget to create" + name="Widget Type", + default='', + description="Choose the type of the widget to create" ) - @classmethod - def parameters_ui(self, layout, params): + def parameters_ui(cls, layout, params): col = layout.column() col.label(text='This rig type does not add the ORG prefix.') col.label(text='Manually add ORG, MCH or DEF as needed.') - self.add_relink_constraints_ui(layout, params) + cls.add_relink_constraints_ui(layout, params) pbone = bpy.context.active_pose_bone @@ -173,8 +181,8 @@ class Rig(BaseRig, RelinkConstraintsMixin): layout_widget_dropdown(layout, params, "optional_widget_type") -#add_parameters = InstanceRig.add_parameters -#parameters_ui = InstanceRig.parameters_ui +# add_parameters = InstanceRig.add_parameters +# parameters_ui = InstanceRig.parameters_ui def create_sample(obj): diff --git a/rigify/rigs/basic/super_copy.py b/rigify/rigs/basic/super_copy.py index fc4b4d33..450bda2c 100644 --- a/rigify/rigs/basic/super_copy.py +++ b/rigify/rigs/basic/super_copy.py @@ -15,21 +15,27 @@ class Rig(BaseRig, RelinkConstraintsMixin): """ A "copy" rig. All it does is duplicate the original bone and constrain it. This is a control and deformation rig. - """ - def find_org_bones(self, pose_bone): - return pose_bone.name + bones: BaseRig.ToplevelBones[str, str, str, str] + + org_name: str + + make_control: bool + make_widget: bool + make_deform: bool + + def find_org_bones(self, pose_bone) -> str: + return pose_bone.name def initialize(self): """ Gather and validate data about the rig. """ - self.org_name = strip_org(self.bones.org) + self.org_name = strip_org(self.bones.org) self.make_control = self.params.make_control - self.make_widget = self.params.make_widget - self.make_deform = self.params.make_deform - + self.make_widget = self.params.make_widget + self.make_deform = self.params.make_deform def generate_bones(self): bones = self.bones @@ -42,7 +48,6 @@ class Rig(BaseRig, RelinkConstraintsMixin): if self.make_deform: bones.deform = self.copy_bone(bones.org, make_deformer_name(self.org_name), bbone=True) - def parent_bones(self): bones = self.bones @@ -54,14 +59,12 @@ class Rig(BaseRig, RelinkConstraintsMixin): if self.make_control and new_parent: self.set_bone_parent(bones.ctrl, new_parent) - def configure_bones(self): bones = self.bones if self.make_control: self.copy_bone_properties(bones.org, bones.ctrl) - def rig_bones(self): bones = self.bones @@ -76,52 +79,50 @@ class Rig(BaseRig, RelinkConstraintsMixin): if self.make_deform: self.relink_move_constraints(bones.org, bones.deform, prefix='DEF:') - def generate_widgets(self): bones = self.bones if self.make_control: # Create control widget if self.make_widget: - create_registered_widget(self.obj, bones.ctrl, self.params.super_copy_widget_type or 'circle') + create_registered_widget(self.obj, bones.ctrl, + self.params.super_copy_widget_type or 'circle') else: create_bone_widget(self.obj, bones.ctrl) - @classmethod - def add_parameters(self, params): + def add_parameters(cls, params): """ Add the parameters of this rig type to the RigifyParameters PropertyGroup """ params.make_control = bpy.props.BoolProperty( - name = "Control", - default = True, - description = "Create a control bone for the copy" + name="Control", + default=True, + description="Create a control bone for the copy" ) params.make_widget = bpy.props.BoolProperty( - name = "Widget", - default = True, - description = "Choose a widget for the bone control" + name="Widget", + default=True, + description="Choose a widget for the bone control" ) params.super_copy_widget_type = bpy.props.StringProperty( - name = "Widget Type", - default = 'circle', - description = "Choose the type of the widget to create" + name="Widget Type", + default='circle', + description="Choose the type of the widget to create" ) params.make_deform = bpy.props.BoolProperty( - name = "Deform", - default = True, - description = "Create a deform bone for the copy" + name="Deform", + default=True, + description="Create a deform bone for the copy" ) - self.add_relink_constraints_params(params) - + cls.add_relink_constraints_params(params) @classmethod - def parameters_ui(self, layout, params): + def parameters_ui(cls, layout, params): """ Create the ui for the rig parameters. """ layout.prop(params, "make_control") @@ -136,7 +137,7 @@ class Rig(BaseRig, RelinkConstraintsMixin): layout.prop(params, "make_deform") - self.add_relink_constraints_ui(layout, params) + cls.add_relink_constraints_ui(layout, params) if params.relink_constraints and (params.make_control or params.make_deform): col = layout.column() -- cgit v1.2.3