4
$\begingroup$

I have made a new object for the Add > Mesh menu and I would like to unregister it but when I try to with:

if __name__ == "__main__":
   unregister()

I get the following error:

Traceback (most recent call last):
  File "\add_tetrahedron.py", line 63, in <module>
    register()
  File "\add_tetrahedron.py", line 59, in unregister
    bpy.utils.unregister_class(OBJECT_OT_add_object)
RuntimeError: unregister_class(...):, missing bl_rna attribute from 'OrderedMeta' instance (may not be registered)

I've tried looking for this error but, I can't find what I'm doing wrong. I can't find anything about bl_rna anywhere.

I'm using Blender 2.79b

The register functions look like this:

# Registration

def add_object_button(self, context):
    self.layout.operator(
        OBJECT_OT_add_object.bl_idname,
        text="Tetrahedron",
        icon='PLUGIN')

def register():
    bpy.utils.register_class(OBJECT_OT_add_object)
    bpy.types.INFO_MT_mesh_add.append(add_object_button)


def unregister():
    bpy.utils.unregister_class(OBJECT_OT_add_object)
    bpy.types.INFO_MT_mesh_add.remove(add_object_button)

if __name__ == "__main__":
    register()
$\endgroup$
  • $\begingroup$ the register() function works just fine. $\endgroup$ – Whitequill Riclo Mar 15 '19 at 15:35
6
$\begingroup$

Consult python docs for a better explanation

Since there is no main() function in Python, when the command to run a python program is given to the interpreter, the code that is at level 0 indentation is to be executed. However, before doing that, it will define a few special variables. __name__ is one such special variable. If the source file is executed as the main program, the interpreter sets the __name__ variable to have a value “__main__”.

If this file is being imported from another module, __name__ will be set to the module’s name. __name__ is a built-in variable which evaluates to the name of the current module. Thus it can be used to check whether the current script is being run on its own or being imported somewhere else by combining it with if statement, as shown below.

if __name__ == "__main__":
    register()

which when run from text editor in above case registers the class OBJECT_OT_add_object When run again it has "no idea" that it is the same class as registered before. ( Hence the error if you try to unregister)

If however the class is registered when enabled as an addon it will be in that addon modules namespace my_addon.OBJECT_OT_add_object (ie __name__ == "my_addon") and will be the same class when unregistered from the addon.

This is included to test scripts in the text editor. Removing it will have no consequence if installed as an addon.

Have a feeling an issue here is:

When testing such scripts it has the tendency to append and append and append the item to the menu.

A solution to this is bpy.ops.script.reload() which in 2.7x has the shortcut F8 or can be run in the python console. Recommend writing a little script to prepend it to the text editor and console headers for convenience

EDIT In 2.8 reload scripts is also available via the Blender > System > Reload Scripts menu.

Import the text script as a module

Further to this. To test a script in the python console. For example the simple panel template.

This will give the script a "namespace"

>>> foo = D.texts['ui_panel_simple.py'].as_module()

Can call the register method

>>> foo.register()

and then later unregister with

>>> foo.unregister()

somewhat more closely emulating it being an addon.

$\endgroup$
  • 1
    $\begingroup$ Damn, When testing addons from the text editor menus get appended over and over again, bpy.ops.script.reload() will be a life saver. Thanks! $\endgroup$ – Duarte Farrajota Ramos Jun 16 '20 at 11:01
  • 1
    $\begingroup$ Well well well it's the new heavy hitter in the python questions. Had to laugh at the +4 to overscore for an underscore.. In 2.8 reload scripts is also available via the Blender > System > Reload Scripts menu. $\endgroup$ – batFINGER Jun 16 '20 at 11:08
  • $\begingroup$ Eheh low hanging fruit, I know. Finally started dipping my toes in Blender Python,and quite enjoying it, but still very green at it. I knew of the menu entry, but calling it from script directly saves some clicks $\endgroup$ – Duarte Farrajota Ramos Jun 16 '20 at 11:15
  • 1
    $\begingroup$ Go in up to your knees with this one (Needs that how to add images link btw) Going by the picture not sure how would do this via the UI, .. delete a hole and grid fill? Reckon you will enjoy scripting coming from your extensive knowledge on how to use the UI to get things done. $\endgroup$ – batFINGER Jun 16 '20 at 11:23
2
$\begingroup$

You can get your registered class via types objects. For example if you have registered your own node tree:

class MyCustomTree(bpy.types.NodeTree):
    bl_idname = 'CustomTreeType'
    bl_label = "Custom Node Tree"
    bl_icon = 'NODETREE'

bpy.utils.register_class(MyCustomTree)

for getting this class you should write next code:

TreeClass = bpy.types.NodeTree.bl_rna_get_subclass_py('CustomTreeType')

Then you can use it for class unregistration

bpy.utils.unregister_class(TreeClass)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.