1
$\begingroup$

I want to have 2 buttons.
One returns to the standard list of addons (includes from the list, disables others). The other one enables mine (and disables all others).

update

Problem is that some addons don't want to just disconnect and the script is interrupted. Is it possible to somehow unregister the addon and then disable it?

There are errors of this type:

Traceback (most recent call last)
Error: Traceback (most recent call last)
AttributeError: 'NoneType' object has no attribute 'keymap_items'

After two days of trying and experimenting , the following script turned out:

import bpy
import addon_utils
import time
# clear console
from os import system
cls = lambda: system('cls')
cls()

bpy.ops.preferences.addon_refresh()

list_default_addon = {
    'add_curve_extra_objects',
    'add_mesh_extra_objects',
    'io_scene_fbx',
    'io_import_images_as_planes',
    'io_curve_svg',
    'io_mesh_uv_layout',
    'io_scene_obj',
    'space_view3d_copy_attributes',
    'mesh_f2',
    'mesh_looptools',
    'node_wrangler',
    'object_boolean_tools',
    'cycles',
    'pie_menu_editor',
    }

# list enabled addon
list_enabled_addon = []
# creating a list enabled addons
for addon in bpy.context.preferences.addons:
    addon_gen_name = addon.module
    list_enabled_addon.append(addon_gen_name)


# list all addon 
list_setup_addon = []
# creating list all addons
for addon_name in addon_utils.modules():
    addon_setup_name = addon_name.__name__
    list_setup_addon.append(addon_setup_name)

for addon_name in addon_utils.modules():
    addon_name_file = addon_name.__name__
    if addon_name_file not in list_default_addon:
        if addon_name_file in list_enabled_addon:
            bpy.ops.preferences.addon_disable(module=addon_name_file)
            time.sleep(0.1)

    elif addon_name_file not in list_enabled_addon:
        if addon_name_file == 'cycles':
            bpy.ops.preferences.addon_enable(module='cycles')
            time.sleep(0.1)
            bpy.context.preferences.addons["cycles"].preferences.compute_device_type = "CUDA" # or "OPENCL"
            bpy.context.scene.cycles.device = "GPU"
            bpy.context.preferences.addons["cycles"].preferences.get_devices()
            print(bpy.context.preferences.addons["cycles"].preferences.compute_device_type)
            for d in bpy.context.preferences.addons["cycles"].preferences.devices:
                d["use"] = 1
                print(d["name"], d["use"])
        else:
            bpy.ops.preferences.addon_enable(module=addon_name_file)
            print('enable', addon_name_file)
            time.sleep(0.1)
    else:
        print('default = enabled', addon_name_file)

bpy.ops.preferences.addon_refresh()
bpy.context.preferences.view.show_addons_enabled_only = True
bpy.data.window_managers['WinMan'].addon_support = {'OFFICIAL', 'COMMUNITY', 'TESTING'}
bpy.data.window_managers['WinMan'].addon_search = ''
bpy.data.window_managers['WinMan'].addon_filter = 'User'
# save preferences
bpy.ops.wm.save_userpref()
$\endgroup$

2 Answers 2

2
$\begingroup$

Here is a complete addon with two buttons to use to swap between the default addons and your list of addons. I've used the list from your question as the second set of addons and I've assumed that the addons that were enabled when you started your blender session is the 'default' set. You can change that by replacing my code that builds the default set list with a list, like the one used for your set of addons.

I've used global variables in this, because it is example code. You'll probably want to replace those with properties or some other means of communication.

You could make a serious addon from this by allowing the user to edit the list of acceptable addons, and by supporting selection of sets of addons; but this version is meant to demonstrate the principle.

I tried using the function from addon_utils to mass disable addons, but it didn't seem to work as expected, so I've replaced it with loops.

This code could also stand to be refactored, as the two operators have nearly identical logic, except with the lists swapped.

As written the buttons will be displayed in the 3D Viewport side panel in a "TLA" tab. You'll probably want to change that as well.

# Copyright 2022 Martin Fouts
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# 

# Very small add on to start from

bl_info = {
    "name" : "Switch addons",
    "description" : "Switch between two sets of addons",
    "author" : "Marty",
    "version" : (0, 0, 1),
    "blender" : (2, 80, 0),
    "location" : "View3D",
    "warning" : "",
    "support" : "COMMUNITY",
    "doc_url" : "",
    "category" : "3D View"
}

import bpy
from bpy.types import Operator
from bpy.types import Panel
from bpy.types import Preferences

default_addons = None

using_my_addons = False

my_addons = {
    "add_curve_extra_objects",
    "add_mesh_extra_objects",
    "io_scene_fbx",
    "io_import_images_as_planes",
    "io_curve_svg",
    "io_mesh_uv_layout",
    "io_scene_obj",
    "space_view3d_copy_attributes",
    "mesh_f2",
    "mesh_looptools",
    "node_wrangler",
    "object_boolean_tools",
    "cycles",
}

def get_enabled():
    """ Get a list of all addons that are currently enabled """
    addon_list = []
    for addon in bpy.context.preferences.addons:
        addon_list.append(addon.module)
    return addon_list

class TLA_OT_use_my_addons(Operator):
    """ Switch to my set of addons """
    bl_idname = "addons.mine"
    bl_label = "Use my addons"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return True

    def execute(self, context):
        global default_addons, my_addons, using_my_addons

        if using_my_addons:
            return {'FINISHED'}

        default_addons = get_enabled()
        for addon in default_addons:
            bpy.ops.preferences.addon_disable(module=addon)

        for addon in my_addons:
            bpy.ops.preferences.addon_enable(module=addon)

        using_my_addons = True

        return {'FINISHED'}

class TLA_OT_use_default_addons(Operator):
    """ Switch to the default set of addons """
    bl_idname = "addons.default"
    bl_label = "Use default addons"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return True

    def execute(self, context):
        global default_addons, my_addons, using_my_addons

        if not using_my_addons:
            return {'FINISHED'}

        for addon in my_addons:
            bpy.ops.preferences.addon_disable(module=addon)

        using_my_addons = False;

        for addon in default_addons:
            bpy.ops.preferences.addon_enable(module=addon)

        return {'FINISHED'}


class TLA_PT_sidebar(Panel):
    """Display addon buttons"""
    bl_label = "Addon sets"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "TLA"

    def draw(self, context):
        col = self.layout.column(align=True)
        prop = col.operator(TLA_OT_use_my_addons.bl_idname)
        prop = col.operator(TLA_OT_use_default_addons.bl_idname)

 
classes = [
    TLA_OT_use_my_addons,
    TLA_OT_use_default_addons,
    TLA_PT_sidebar,
]

def register():
    for c in classes:
        bpy.utils.register_class(c)


def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)


if __name__ == '__main__':
    register()
$\endgroup$
3
  • $\begingroup$ I planned to make 2 buttons. On one there will be a list of default_list_addon, on the other there will be a list of my_list_addon. I updated the information in the question at the same time as your answer ) $\endgroup$
    – gkhwvjxtc
    Jun 6, 2022 at 20:14
  • $\begingroup$ This addon makes two buttons, but you're not going to be able to put the whole list on the button, only a label indicating whether it's the default, or the other list. If you want both lists hardwired, simply set default_addons to the list you want and remove the call to get_enabled(). $\endgroup$ Jun 6, 2022 at 20:17
  • $\begingroup$ Thank you so much for your addon, but it does not suit me - it is too technical for me and I do not understand what is happening in it. If I need to change or add something, I won't be able to do it with my python knowledge level) $\endgroup$
    – gkhwvjxtc
    Jun 7, 2022 at 18:53
1
$\begingroup$

You are doing everything sort of correctly. In your loop addon.module is a string - it's the addon's name, so you don't need anything else around it when using the operator:

bpy.ops.preferences.addon_enable(module=addon.module) should work.

Also you should check if the addon is in your list, not if the addon is the list, so that would be

if addon.module in default_list_addon:

Also there is no point to make the list every time for each loop, you should make the list before the for loop begins.

You should probably also check if the add-on from your list exists in Blender.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .