VScode and JacquesLucke's blender_vscode

2»

Comments

  • @bdamay said:
    OK i think i get it . I shouldn't try to reregister PropertyGroup - i will investigate why i get this class from inspecting submodule

    Indeed there is no need to unregister the default Blender classes such as bpy.types.PropertyGroup, bpy.types.Operator, only their subclasses.
    Sometimes they may get imported in module namespace, e.g. with from bpy.types import PropertyGroup.

  • Moving forward, i reduced the inspect scope to fit class definitions on the actual submodule inspected and got rid of most of errors i encountered so far, but not all if i widen the scope
    I'm still having problems with some classes that fails to reregister . Here's one example with BIMProjectProperties from blenderbim.bim.module.project.prop module

    >>> cl = blenderbim.bim.module.project.prop.BIMProjectProperties
    >>> bpy.utils.unregister_class(cl)
    >>> bpy.utils.register_class(cl)
    TypeError: CollectionProperty(...): expected an RNA type, failed with: RuntimeError: , missing bl_rna attribute from 'RNAMetaPropGroup' instance (may not be registered)
    
    Traceback (most recent call last):
      File "<blender_console>", line 1, in <module>
    ValueError: bpy_struct "BIMProjectProperties" registration error: 'library_elements' CollectionProperty could not register (see previous error) 
    

    @Andrej730 do you have an idea ?

  • I have to leave it for now, but i pushed the code on github here if you want to test it. (https://github.com/bdamay/bbim-reload-addon)
    I added the hability to fill a custom basename for modules in case it is needed to reload from blenderbim.bim.tools.

  • @bdamay said:
    I'm still having problems with some classes that fails to reregister . Here's one example with BIMProjectProperties from blenderbim.bim.module.project.prop module

    Tried to run the code below in the fresh Blender session and there are no errors.

    import bpy
    import blenderbim
    cl = blenderbim.bim.module.project.prop.BIMProjectProperties
    bpy.utils.unregister_class(cl)
    bpy.utils.register_class(cl)
    

    From your error description it seems there is a problem with library_elements ('library_elements' CollectionProperty could not register (see previous error)), I guess it's because it's a CollectionProperty that's using other PropertyGroup as it's type - LibraryElement. So, in that case LibraryElement should be reregistered first.

    So, the way to reproduce this error is more like:

    import bpy
    import blenderbim
    cl = blenderbim.bim.module.project.prop.BIMProjectProperties
    bpy.utils.unregister_class(cl)
    bpy.utils.unregister_class(blenderbim.bim.module.project.prop.LibraryElement)
    bpy.utils.register_class(cl)
    
  • @Andrej730 said:

    Tried to run the code below in the fresh Blender session and there are no errors.

    import bpy
    import blenderbim
    cl = blenderbim.bim.module.project.prop.BIMProjectProperties
    bpy.utils.unregister_class(cl)
    bpy.utils.register_class(cl)
    

    I ran it my self on fresh start and there is no errors, you're right.
    But, it looks like something breaks into blenderbim anyway as the class doesn't seem to be properly registered.
    Once the lines have been executed (without errors), i tried to start a fresh ifc project - and ther it fails with lots of errors regarding project property class.

    To make Blender BIM work again i needed to unactivate reactivate the whole BlenderBIM add-on. Looks like i'm not really getting nowhere safe. :-(

  • @bdamay said:
    I ran it my self on fresh start and there is no errors, you're right.
    But, it looks like something breaks into blenderbim anyway as the class doesn't seem to be properly registered.
    Once the lines have been executed (without errors), i tried to start a fresh ifc project - and ther it fails with lots of errors regarding project property class.

    It's hard to tell what's the issue, need some isolated example to reproduce this.

  • Well the good thing is for 2 cases at least (demo, project.operator) the plugin looks like working fine. It might be useful anyway.
    I might have been to hungry willing for more, there are sure things i don't understand enough yet to achieve this.
    Thanks for your kind help

  • @bdamay I think there is a bug, the code below (from here) will never reload more than 1 class since during reloading of the 1st class it will reload the module and the next class will be retrieved from already reloaded module in cl = getattr(module, cn) and cl.is_registered will always be False, so no other classes will be reloaded.

            # reregistering classes
            for cn in class_names:
                cl = getattr(module, cn)
                if hasattr(cl, 'is_registered'):
                    if cl.is_registered and module_name == cl.__module__:
                        bpy.utils.unregister_class(cl)
                        importlib.reload(module)
                        cl = getattr(module, cn)
                        bpy.utils.register_class(cl)
                        print('- Registered Class', cn)
    

    You can reproduce it by running the addon with basename blenderbim.bim.module and module cost.ui, the output will contain just 1 class though there are 11 Blender based classes present in this module (5 Panels and 6 UILists):

    ------------------------------------------------------------
    Reregistering BBIM utility
    Module blenderbim.bim.module.cost.ui
    - Registered Class BIM_PT_Costing_Tools
    done
    ------------------------------------------------------------
    
    bdamay
  • noobie alert.
    ran...

    import importlib
    import bpy
    
    reregister_classes = {
        "bonsai.bim.module.drawing.svgwriter": ("SvgWriter", ),
    }
    
    for module_name, classes in reregister_classes.items():
        module = importlib.import_module(module_name)
        for class_name in classes:
            class_obj = getattr(module, class_name)
            bpy.utils.unregister_class(class_obj)
    
        importlib.reload(module)
    
        for class_name in classes:
            class_obj = getattr(module, class_name)
            bpy.utils.register_class(class_obj)
    

    got this error.

    Python: Traceback (most recent call last):
      File "D:\Dropbox\Troubleshooting\20241107 - fill-bg raster\20241107 - fill-bg raster.blend\Text", line 12, in <module>
    RuntimeError: unregister_class(...):, missing bl_rna attribute from 'type' instance (may not be registered)
    
    
  • Well, you're trying to unregister classes that are not derived from a blender class. So it's missing a bunch of stuff the unregister function is looking for. That is my first guess.

  • Is relative to @Andrej730 nifty script. Probably botching how to use it.

  • edited November 2024

    Yes. That is for deregistering a Blender operator. i.e. something derived using for example: class ActivateModel(bpy.types.Operator):
    In the svgwriter.py file are two classes:
    class SvgWriter:
    and
    class External(svgwrite.container.Group):
    Neither of these get registered with Blender, so you cannot unregister them. In the for class_name in classes: loop there should be a test to ensure the class is a blender class. This assumes you are wanting to refresh other things. If you're just refreshing svgwriter then you should just remove that for loop as it isn't appropriate. [Correction] Add the test in both for loops, or remove both for loops if just poking SvgWriter.

    theoryshaw
  • That kinda makes sense.
    Not sure how to modify the script.
    Basically looking to not have to restart blender every time. :)

  • Is it just the SVGWriter you are changing? If so, just delete the two for loops - you don't need them. If you are wanting to do multiple modules that could contain items that are and are not blender types, then you'll need something like (warning! untested code ;-):

        for class_name in classes:
            class_obj = getattr(module, class_name)
            if class_obj.__class__.__name__ == 'RNAMeta':
                bpy.utils.unregister_class(class_obj)
    

    and

        for class_name in classes:
            class_obj = getattr(module, class_name)
            if class_obj.__class__.__name__ == 'RNAMeta':
                bpy.utils.register_class(class_obj)
    
    theoryshaw
  • edited November 2024

    @theoryshaw said:
    That kinda makes sense.
    Not sure how to modify the script.
    Basically looking to not have to restart blender every time. :)

    @sjb007 is correct, SvgWriter is not Blender class, so there is no need to register/unregister it. You need to importlib.reload svgwriter module and reregister Blender operators that are going to use updated SvgWriter (operator CreateDrawing), so they can pick up reloaded class reference.

    theoryshaw
  • Thank you both! This shaves hours. :)
    Tweaked with a little AI help...

    import importlib
    import bpy
    
    # Dictionary of modules with Blender-specific classes to reregister
    reregister_classes = {
        "bonsai.bim.module.drawing.svgwriter": ("SvgWriter", ),  # Update as needed
    }
    
    for module_name, classes in reregister_classes.items():
        module = importlib.import_module(module_name)
    
        # Only try to unregister/register classes that are Blender types
        for class_name in classes:
            class_obj = getattr(module, class_name)
            if hasattr(class_obj, 'bl_rna'):  # Check if it's a Blender class
                bpy.utils.unregister_class(class_obj)
    
        importlib.reload(module)
    
        for class_name in classes:
            class_obj = getattr(module, class_name)
            if hasattr(class_obj, 'bl_rna'):  # Check if it's a Blender class
                bpy.utils.register_class(class_obj)
    
    
  • Unabashed use of AI. :)

    bl_info = {
        "name": "Reload Multiple Modules Tool",
        "blender": (2, 80, 0),
        "category": "Development",
    }
    
    import bpy
    import importlib
    
    # Define a Property Group for each module-class pair
    class ReloadModuleClassPair(bpy.types.PropertyGroup):
        module_name: bpy.props.StringProperty(name="Module Name")
        class_name: bpy.props.StringProperty(name="Class Name")
    
    # Operator to reload the modules
    class RELOADMULTIPLEMODULES_OT_ReloadModules(bpy.types.Operator):
        """Reload the specified modules and classes"""
        bl_idname = "reloadmultiplemodules.reload_modules"
        bl_label = "Reload Modules"
    
        def execute(self, context):
            props = context.scene.reload_multiple_modules_tool_props
            for pair in props.module_class_pairs:
                module_name = pair.module_name.strip()
                class_name = pair.class_name.strip()
    
                if not module_name or not class_name:
                    continue
    
                try:
                    # Import the module
                    module = importlib.import_module(module_name)
    
                    # Get the class object from the module
                    class_obj = getattr(module, class_name)
    
                    # Unregister if it's a Blender type (e.g., bpy.types.Operator, Panel)
                    if hasattr(class_obj, 'bl_rna'):
                        bpy.utils.unregister_class(class_obj)
    
                    # Reload the module
                    importlib.reload(module)
    
                    # Get the refreshed class object
                    class_obj = getattr(module, class_name)
    
                    # Register if it's a Blender type
                    if hasattr(class_obj, 'bl_rna'):
                        bpy.utils.register_class(class_obj)
    
                    self.report({'INFO'}, f"Reloaded {class_name} from {module_name}")
    
                except Exception as e:
                    self.report({'ERROR'}, f"Failed to reload {class_name} from {module_name}: {e}")
    
            return {'FINISHED'}
    
    # Panel to show the interface for adding modules and classes
    class RELOADMULTIPLEMODULES_PT_Panel(bpy.types.Panel):
        """Creates a Panel in the Object properties window"""
        bl_label = "Reload Multiple Modules Tool"
        bl_idname = "RELOADMULTIPLEMODULES_PT_panel"
        bl_space_type = 'VIEW_3D'
        bl_region_type = 'UI'
        bl_category = 'Development'
    
        def draw(self, context):
            layout = self.layout
            props = context.scene.reload_multiple_modules_tool_props
    
            # Display the module-class pairs with a dynamic UI
            for i, pair in enumerate(props.module_class_pairs):
                row = layout.row()
                row.prop(pair, "module_name")
                row.prop(pair, "class_name")
    
            # Add button to add a new pair
            layout.operator("reloadmultiplemodules.add_module_class_pair", text="Add Module-Class Pair")
    
            # Reload button
            layout.operator("reloadmultiplemodules.reload_modules", text="Reload Modules")
    
    # Operator to add a new module-class pair
    class RELOADMULTIPLEMODULES_OT_AddModuleClassPair(bpy.types.Operator):
        """Add a new module-class pair"""
        bl_idname = "reloadmultiplemodules.add_module_class_pair"
        bl_label = "Add Module-Class Pair"
    
        def execute(self, context):
            props = context.scene.reload_multiple_modules_tool_props
            # Add a new entry to the list
            props.module_class_pairs.add()
            return {'FINISHED'}
    
    # The PropertyGroup for the scene to hold the list of module-class pairs
    class ReloadMultipleModulesToolProperties(bpy.types.PropertyGroup):
        module_class_pairs: bpy.props.CollectionProperty(type=ReloadModuleClassPair)
    
    def register():
        bpy.utils.register_class(ReloadModuleClassPair)
        bpy.utils.register_class(RELOADMULTIPLEMODULES_OT_ReloadModules)
        bpy.utils.register_class(RELOADMULTIPLEMODULES_PT_Panel)
        bpy.utils.register_class(RELOADMULTIPLEMODULES_OT_AddModuleClassPair)
        bpy.utils.register_class(ReloadMultipleModulesToolProperties)
        bpy.types.Scene.reload_multiple_modules_tool_props = bpy.props.PointerProperty(type=ReloadMultipleModulesToolProperties)
    
    def unregister():
        bpy.utils.unregister_class(ReloadModuleClassPair)
        bpy.utils.unregister_class(RELOADMULTIPLEMODULES_OT_ReloadModules)
        bpy.utils.unregister_class(RELOADMULTIPLEMODULES_PT_Panel)
        bpy.utils.unregister_class(RELOADMULTIPLEMODULES_OT_AddModuleClassPair)
        bpy.utils.unregister_class(ReloadMultipleModulesToolProperties)
        del bpy.types.Scene.reload_multiple_modules_tool_props
    
    if __name__ == "__main__":
        register()
    
    
  • @theoryshaw @Andrej730 said it, but maybe didn't emphasize enough... Order matters. Suggestion for your UI would be to add deletion of pairs, and the ability to order the classes. An alternative brute force would be to run the reload loop twice. That way order wouldn't matter, because everything would be up-to-date for the second go around.

    theoryshaw
  • @sjb007 said:
    @theoryshaw @Andrej730 said it, but maybe didn't emphasize enough... Order matters. Suggestion for your UI would be to add deletion of pairs, and the ability to order the classes. An alternative brute force would be to run the reload loop twice. That way order wouldn't matter, because everything would be up-to-date for the second go around.

    Thanks @sjb007.
    ping @bdamay. I wonder if this was the cause of some of the problems you were experiencing?

  • I have a fork with some fixed issues, perhaps it can help - https://github.com/Andrej730/bbim-reload-addon
    E.g. you can reload svgwriter and drawing operators like this:

    theoryshawMassimo
Sign In or Register to comment.