2025-07-01

This commit is contained in:
2026-03-17 14:30:01 -06:00
parent f9a22056dd
commit 62b5978595
4579 changed files with 1257472 additions and 0 deletions
@@ -0,0 +1,51 @@
import bpy
from .info_messages import RENAMING_MESSAGES, WarningError_MESSAGES, INFO_MESSAGES
from .renaming_panels import VIEW3D_PT_tools_renaming_panel, VIEW3D_PT_tools_type_suffix, VIEW3D_OT_SetVariable, \
VIEW3D_OT_RenamingPopupOperator, OBJECT_MT_suffix_prefix_presets, AddPresetRenamingPresets
from .renaming_panels import panel_func
from .renaming_popup import VIEW3D_PT_renaming_popup, VIEW3D_PT_info_popup, VIEW3D_PT_error_popup
from .renaming_variables import RENAMING_MT_variableMenu, VIEW3D_OT_inputVariables
from .ui_helpers import PREFERENCES_OT_open_addon
classes = (
RENAMING_MT_variableMenu,
VIEW3D_OT_inputVariables,
VIEW3D_PT_error_popup,
VIEW3D_PT_info_popup,
VIEW3D_PT_renaming_popup,
OBJECT_MT_suffix_prefix_presets,
AddPresetRenamingPresets,
VIEW3D_PT_tools_renaming_panel,
VIEW3D_PT_tools_type_suffix,
VIEW3D_OT_SetVariable,
VIEW3D_OT_RenamingPopupOperator,
PREFERENCES_OT_open_addon,
)
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
bpy.types.VIEW3D_PT_tools_type_suffix.prepend(panel_func)
id_store = bpy.types.Scene
id_store.renaming_messages = RENAMING_MESSAGES()
id_store.renaming_error_messages = WarningError_MESSAGES()
id_store.renaming_info_messages = INFO_MESSAGES()
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
id_store = bpy.types.Scene
del id_store.renaming_messages
del id_store.renaming_error_messages
del id_store.renaming_info_messages
@@ -0,0 +1,55 @@
class MESSAGE:
"""messages parent class"""
message = []
@classmethod
def add_message(cls):
return
@classmethod
def get_messages(cls):
return cls.message
@classmethod
def print_all(cls):
print("Print All " + str(list(cls.message)))
return
@classmethod
def clear(cls):
cls.message = []
@classmethod
def draw(cls, context):
return
class INFO_MESSAGES(MESSAGE):
"""Custom info messages"""
@classmethod
def add_message(cls, assetName, message='', obType=False, obIcon=False):
message_dict = {'assetName': assetName, 'message': message, 'obType': obType, 'obIcon': obIcon}
cls.message.append(message_dict)
return
class WarningError_MESSAGES(MESSAGE):
"""Custom error warning messages"""
@classmethod
def add_message(cls, message='', isError=False):
message_dict = {'message': message, 'isError': isError}
cls.message.append(message_dict)
return
class RENAMING_MESSAGES(MESSAGE):
"""Custom renaming messages"""
message = []
@classmethod
def add_message(cls, oldName, new_name=None, obType=False, obIcon=False, warning=False):
message_dict = {'oldName': oldName, 'new_name': new_name, 'obType': obType, 'obIcon': obIcon, 'warning': warning}
cls.message.append(message_dict)
return
@@ -0,0 +1,359 @@
import bpy
from bl_operators.presets import AddPresetBase
from bpy.props import StringProperty
from bpy.types import Operator, Menu
from ..ui.renaming_variables import RENAMING_MT_variableMenu
# Selected objects are renamed directly
types_selected = ('OBJECT', 'ADDOBJECTS', 'BONE')
# Components of the selected objects are renamed
types_of_selected = (
'MATERIAL', 'DATA', 'VERTEXGROUPS', 'PARTICLESYSTEM', 'SHAPEKEYS', 'MODIFIERS', 'UVMAPS',
'COLORATTRIBUTES', 'ATTRIBUTES', 'ACTIONS')
def draw_renaming_panel(layout, context):
scene = context.scene
row = layout.row(align=True)
row.label(text="Target")
row = layout.row(align=True)
row.prop(scene, "renaming_object_types", text="")
# SELECTED
if str(scene.renaming_object_types) == 'OBJECT':
layout.prop(scene, "renaming_object_types_specified", expand=True)
if str(scene.renaming_object_types) in types_of_selected:
layout.prop(scene, "renaming_only_selection", text="Only Of Selected Objects")
elif str(scene.renaming_object_types) in types_selected:
layout.prop(scene, "renaming_only_selection", text="Only Selected")
elif str(scene.renaming_object_types) == 'COLLECTION':
if bpy.context.space_data.type == 'OUTLINER':
row = layout.row(align=True)
row.prop(scene, "renaming_only_selection", text="Only Selected")
else:
col = layout.column(align=True)
row = col.row(align=True)
row.enabled = False
row.prop(scene, "renaming_only_selection", text="Only Selected")
row = col.row(align=True)
row.enabled = False
row.label(text="Open from Outliner", icon="ERROR")
box = layout
# Sorting
if str(scene.renaming_object_types) not in ['COLLECTION', 'IMAGE']:
col = box.column(align=True)
col.prop(scene, "renaming_sorting")
if scene.renaming_sorting:
if str(scene.renaming_object_types) == 'BONE':
col.prop(scene, "renaming_sort_bone_enum", expand=True)
else:
col.prop(scene, "renaming_sort_enum", expand=True)
col.prop(scene, "renaming_sort_reverse")
layout.separator(type='LINE')
layout.label(text="Rename")
# NEW NAME
col = layout.column(align=True)
col.prop(scene, "renaming_use_enumerate")
row = col.row(align=True)
split = row.split(factor=0.6, align=True)
split.prop(scene, "renaming_new_name", text='')
split = split.split(factor=0.75, align=True)
split.prop(scene, "renaming_numerate", text='')
split.operator("object.renaming_set_variable", text="@").inputBox = "new_name"
row = col.row()
row.operator("renaming.name_replace", icon="FORWARD")
# SEARCH REPLACE
layout.separator()
layout.label(text="Search and Replace")
split = layout.split(factor=0.5, align=True)
col_a = split.column(align=True)
col_b = split.column(align=True)
row = col_a.row(align=True)
row.prop(scene, "renaming_useRegex")
row = col_b.row(align=True)
row.enabled = not scene.renaming_useRegex
row.prop(scene, "renaming_matchcase")
col = layout.column(align=True)
split = col.split(factor=0.9, align=True)
split.prop(scene, "renaming_search", text='Search')
split.operator("object.renaming_set_variable", text="@").inputBox = "search"
split = col.split(factor=0.9, align=True)
split.prop(scene, "renaming_replace", text='Replace')
split.operator("object.renaming_set_variable", text="@").inputBox = "replace"
if scene.renaming_object_types == 'BONE':
if context.mode == 'POSE' or context.mode == 'EDIT_ARMATURE':
row = layout.row(align=True)
row.operator("renaming.search_select", icon="RESTRICT_SELECT_OFF")
elif scene.renaming_object_types == 'OBJECT':
row = layout.row(align=True)
row.operator("renaming.search_select", icon="RESTRICT_SELECT_OFF")
row = layout.row(align=True)
row.operator("renaming.search_replace", icon="FILE_REFRESH")
###############################################
layout.separator()
layout.label(text="Add Prefix and Suffix")
# REFIX SUFFIX
col = layout.column(align=True)
split = col.split(factor=0.9, align=True)
split.prop(scene, "renaming_prefix", text='')
split.operator("object.renaming_set_variable", text="@").inputBox = "prefix"
col.operator("renaming.add_prefix", icon="REW")
col = layout.column(align=True)
split = col.split(factor=0.9, align=True)
split.prop(scene, "renaming_suffix", text='')
split.operator("object.renaming_set_variable", text="@").inputBox = "suffix"
col.operator("renaming.add_suffix", icon="FF")
###############################################
layout.separator()
layout.label(text="Trim")
# TRIM
col = layout.column(align=True)
col.prop(scene, "renaming_trim_indices",index=0,text="First")
col.prop(scene, "renaming_trim_indices",index=1,text="Last")
row = layout.row(align=True)
row.operator("renaming.trim_string", icon="X")
###############################################
layout.separator()
layout.label(text="Other")
row = layout.row(align=True)
row.operator("renaming.numerate", icon="LINENUMBERS_ON")
if str(scene.renaming_object_types) in ('DATA', 'OBJECT', 'ADDOBJECTS'):
layout.separator()
layout.label(text="Data Name")
col = layout.column(align=True)
split = col.split(factor=0.9, align=True)
split.prop(scene, "renaming_suffix_prefix_data_02", text='')
split.operator("object.renaming_set_variable", text="@").inputBox = "dataFromObj"
col.operator("renaming.data_name_from_obj", icon="MOD_DATA_TRANSFER")
def panel_func(self, context):
layout = self.layout
row = layout.row(align=True)
row.menu('OBJECT_MT_suffix_prefix_presets', text=OBJECT_MT_suffix_prefix_presets.bl_label)
row.operator(AddPresetRenamingPresets.bl_idname, text="", icon='ADD')
row.operator(AddPresetRenamingPresets.bl_idname, text="", icon='REMOVE').remove_active = True
class VIEW3D_PT_tools_renaming_panel(bpy.types.Panel):
"""Creates a renaming Panel"""
bl_label = "Simple Renaming"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Rename"
def draw_header(self, context):
layout = self.layout
row = layout.row(align=True)
row.operator("wm.url_open", text="", icon='HELP').url = "https://weisl.github.io/renaming_overview/"
addon_name = get_addon_name()
op = row.operator("preferences.rename_addon_search", text="", icon='PREFERENCES')
op.addon_name = addon_name
op.prefs_tabs = 'UI'
def draw(self, context):
layout = self.layout
draw_renaming_panel(layout, context)
# needed for adding direct link to settings
def get_addon_name():
return "Simple Renaming"
# addon Panel
class VIEW3D_PT_tools_type_suffix(bpy.types.Panel):
"""Creates a renaming Panel"""
bl_label = "Prefix/Suffix by Type"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Rename"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
scene = context.scene
layout = self.layout
layout.prop(scene, "type_pre_sub_only_selection", text="Only Selected Objects")
layout.prop(scene, "renaming_suffix_prefix_type", expand=True)
# layout.prop(scene, "renaming_suffix_prefix_types_specified")
if scene.renaming_suffix_prefix_type == "PRE":
layout.label(text="Add Type Prefix")
else:
layout.label(text="Add Type Suffix")
split = layout.split()
col = split.column()
row = col.row()
row.prop(scene, "renaming_suffix_prefix_empty", text="")
row.operator("renaming.add_suffix_prefix_by_type", text="Empties").option = 'empty'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_geometry", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Meshes").option = 'mesh'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_material", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Materials").option = 'material'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_curve", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Curves").option = 'curve'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_armature", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Armatures").option = 'armature'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_lattice", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Lattices").option = 'lattice'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_data", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Data").option = 'data'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_surfaces", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Surfaces").option = 'surface'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_cameras", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Cameras").option = 'camera'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_lights", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Lights").option = 'light'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_collection", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Collections").option = 'collection'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_text", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Texts").option = 'text'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_gpencil", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Grease Pencil").option = 'gpencil'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_metaball", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Metaballs").option = 'metaball'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_bone", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Bones").option = 'bone'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_speakers", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Speakers").option = 'speakers'
row = col.row()
row.prop(scene, "renaming_suffix_prefix_lightprops", text="")
row.operator('renaming.add_suffix_prefix_by_type', text="Light Probes").option = 'lightprops'
row = col.row()
row.operator('renaming.add_suffix_prefix_by_type', text="Rename All").option = 'all'
class VIEW3D_OT_SetVariable(bpy.types.Operator):
"""Tooltip"""
bl_idname = "object.renaming_set_variable"
bl_label = "Simple Object Operator"
inputBox: StringProperty()
def execute(self, context):
context.scene.renaming_inputContext = self.inputBox
bpy.ops.wm.call_menu(name=RENAMING_MT_variableMenu.bl_idname)
return {'FINISHED'}
class VIEW3D_OT_RenamingPopupOperator(bpy.types.Operator):
bl_idname = "renaming.f_popup_operator"
bl_label = "Simple Renaming"
my_float: bpy.props.FloatProperty(name="Some Floating Point")
my_bool: bpy.props.BoolProperty(name="Toggle Option")
my_string: bpy.props.StringProperty(name="String Value")
def execute(self, context):
print("Dialog Runs")
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self)
class OBJECT_MT_suffix_prefix_presets(Menu):
bl_label = "Type Presets"
preset_subdir = "scene/display"
preset_operator = "script.execute_preset"
draw = Menu.draw_preset
class AddPresetRenamingPresets(AddPresetBase, Operator):
"""Add an Object Display Preset"""
bl_idname = "renaming.sufpreadd_presets"
bl_label = "Add Renaming Preset"
preset_menu = "OBJECT_MT_suffix_prefix_presets"
# variable used for all preset values
preset_defines = [
"scene = bpy.context.scene"
]
# properties to store in the preset
preset_values = [
"scene.renaming_suffix_prefix_empty",
"scene.renaming_suffix_prefix_geometry",
"scene.renaming_suffix_prefix_material",
"scene.renaming_suffix_prefix_curve",
"scene.renaming_suffix_prefix_armature",
"scene.renaming_suffix_prefix_lattice",
"scene.renaming_suffix_prefix_data",
"scene.renaming_suffix_prefix_surfaces",
"scene.renaming_suffix_prefix_cameras",
"scene.renaming_suffix_prefix_lights",
"scene.renaming_suffix_prefix_collection",
"scene.renaming_suffix_prefix_text",
"scene.renaming_suffix_prefix_gpencil",
"scene.renaming_suffix_prefix_metaball",
"scene.renaming_suffix_prefix_bone",
"scene.renaming_suffix_prefix_speakers",
"scene.renaming_suffix_prefix_lightprops",
]
# where to store the preset
preset_subdir = "scene/display"
@@ -0,0 +1,137 @@
import bpy
class VIEW3D_PT_error_popup(bpy.types.Panel):
"""Tooltip"""
bl_idname = "POPUP_PT_error"
bl_label = "Renaming Info"
bl_space_type = "VIEW_3D"
bl_region_type = "WINDOW"
bl_ui_units_x = 30
def draw(self, context):
layout = self.layout
box = layout.box()
wm = context.scene
messages = wm.renaming_error_messages
if len(messages.message) <= 0:
box.label(text="Unknown Error", icon="INFO")
else:
for msg in messages.message:
if msg is not None:
row = box.row(align=False)
# row.alignment = 'EXPAND'
if msg['isError']:
row.label(text=str('Error'), icon='ERROR')
row = box.row(align=False)
row.label(text=str(msg['message']), icon='ERROR')
else:
row.label(text=str('Warning'), icon='ERROR')
row = box.row(align=False)
row.label(text=str(msg['message']), icon='CANCEL')
messages.clear()
return
class VIEW3D_PT_info_popup(bpy.types.Panel):
"""Tooltip"""
bl_idname = "POPUP_PT_info"
bl_label = "Renaming Info"
bl_space_type = "VIEW_3D"
bl_region_type = "WINDOW"
bl_ui_units_x = 30
def draw(self, context):
layout = self.layout
box = layout.box()
wm = context.scene
infos = wm.renaming_info_messages
if len(infos.message) <= 0:
box.label(text="No Objects Validated", icon="INFO")
else:
i = 0
for msg in infos.message:
if msg is not None:
if msg['message'] is not None:
row = box.row(align=True)
row.alignment = 'EXPAND'
if msg['obType'] is not False and msg['obIcon'] is not False:
row.label(text=str(msg['obType']), icon=msg['obIcon'])
# row.label(text = str(msg['obType']), icon = 'INFO')
else:
row.label(text=str(wm.renaming_object_types))
row.label(text=str(msg['assetName']), icon='FILE_TICK')
row.label(text=str(msg['oldName']))
i += 1
infos.clear()
class VIEW3D_PT_renaming_popup(bpy.types.Panel):
"""Tooltip"""
bl_idname = "POPUP_PT_popup"
bl_label = "Renaming Info"
bl_space_type = "VIEW_3D"
bl_region_type = "WINDOW"
bl_ui_units_x = 30
def draw(self, context):
wm = context.scene
layout = self.layout
box = layout.box()
if len(wm.renaming_messages.message) <= 0:
box.label(text="No Objects Renamed", icon="INFO")
else:
i = 0
for msg in wm.renaming_messages.message:
if msg is not None:
if not msg['warning']:
if (msg['new_name'] is not None and msg['oldName'] is not None) and msg['oldName'] != msg[
'new_name']:
if i == 0:
row = box.row(align=True)
row.alignment = 'EXPAND'
row.label(text="Object Type")
row.label(text="New Name")
row.label(text="Old Name")
box.separator(type='LINE')
row = box.row(align=True)
row.alignment = 'EXPAND'
if msg['obType'] is not False and msg['obIcon'] is not False:
row.label(text=str(msg['obType']), icon=msg['obIcon'])
else:
row.label(text=str(wm.renaming_object_types))
row.label(text=str(msg['new_name']), icon='FILE_TICK')
row.label(text=str(msg['oldName']))
i += 1
else: # if msg['warning'] == True
if msg['new_name'] is not None and msg['oldName'] is not None:
box.label(text="Warning", icon="ERROR")
box.label(text=" " + "Name: " + str(msg['oldName']))
box.label(text=" " + msg['warning'])
else:
box.label(text="Warning", icon="ERROR")
box.label(text=" " + msg['warning'])
if i == 0:
box.label(text="No Objects Renamed", icon="INFO")
wm.renaming_messages.clear()
@@ -0,0 +1,103 @@
import bpy
from bpy.props import StringProperty
class RENAMING_MT_variableMenu(bpy.types.Menu):
bl_label = "Renaming Variables"
bl_idname = "MENU_MT_renaming_variables"
def draw(self, context):
layout = self.layout
wm = bpy.context.scene
layout.operator("object.renaming_multivariables", text="RANDOM").renaming_variables = "RANDOM"
layout.operator("object.renaming_multivariables", text="NUMBER").renaming_variables = "NUMBER"
layout.separator()
layout.operator("object.renaming_multivariables", text="LOW").renaming_variables = "LOW"
layout.operator("object.renaming_multivariables", text="HIGH").renaming_variables = "HIGH"
layout.operator("object.renaming_multivariables", text="CAGE").renaming_variables = "CAGE"
layout.separator()
layout.operator("object.renaming_multivariables", text='FILE').renaming_variables = 'FILE'
layout.operator("object.renaming_multivariables", text="TIME").renaming_variables = "TIME"
layout.operator("object.renaming_multivariables", text="DATE").renaming_variables = "DATE"
layout.separator()
layout.operator("object.renaming_multivariables", text="USER1").renaming_variables = "USER1"
layout.operator("object.renaming_multivariables", text="USER2").renaming_variables = "USER2"
layout.operator("object.renaming_multivariables", text="USER3").renaming_variables = "USER3"
if wm.renaming_object_types == 'OBJECT':
layout.separator()
layout.operator("object.renaming_multivariables", text="PARENT").renaming_variables = "PARENT"
layout.operator("object.renaming_multivariables", text="DATA").renaming_variables = "DATA"
layout.operator("object.renaming_multivariables", text="ACTIVE").renaming_variables = "ACTIVE"
layout.operator("object.renaming_multivariables", text='FILE').renaming_variables = 'OBJECT'
layout.operator("object.renaming_multivariables", text="TYPE").renaming_variables = "TYPE"
layout.operator("object.renaming_multivariables", text="COLLECTION").renaming_variables = "COLLECTION"
class VIEW3D_OT_inputVariables(bpy.types.Operator):
"""Tooltip"""
bl_idname = "object.renaming_multivariables"
bl_label = "Simple Object Operator"
renaming_variables: StringProperty()
def execute(self, context):
# wm = context.scene
# replaceName = VariableReplacer.replaceInputString(context, wm.renaming_new_name)
# The print function works fine
renaming_variables = self.renaming_variables
# print (self.renaming_variables)
name_var = ""
# print('T changed to ', renaming_variables)
if renaming_variables == 'FILE':
name_var = "@f"
if renaming_variables == 'OBJECT':
name_var = "@o"
if renaming_variables == "HIGH":
name_var = "@h"
if renaming_variables == "LOW":
name_var = "@l"
if renaming_variables == "CAGE":
name_var = "@b"
if renaming_variables == "DATE":
name_var = "@d"
if renaming_variables == "ACTIVE":
name_var = "@a"
if renaming_variables == "USER1":
name_var = "@u1"
if renaming_variables == "USER2":
name_var = "@u2"
if renaming_variables == "USER3":
name_var = "@u3"
if renaming_variables == "TIME":
name_var = "@i"
if renaming_variables == "TYPE":
name_var = "@t"
if renaming_variables == "PARENT":
name_var = "@p"
if renaming_variables == "DATA":
name_var = "@m"
if renaming_variables == "NUMBER":
name_var = "@n"
if renaming_variables == "RANDOM":
name_var = "@r"
if renaming_variables == "COLLECTION":
name_var = "@c"
scn = context.scene
if scn.renaming_inputContext == 'new_name':
context.scene.renaming_new_name += str(name_var)
if scn.renaming_inputContext == 'prefix':
context.scene.renaming_prefix += str(name_var)
if scn.renaming_inputContext == 'suffix':
context.scene.renaming_suffix += str(name_var)
if scn.renaming_inputContext == 'search':
context.scene.renaming_search += str(name_var)
if scn.renaming_inputContext == 'replace':
context.scene.renaming_replace += str(name_var)
return {'FINISHED'}
@@ -0,0 +1,38 @@
import bpy
from .. import __package__ as base_package
class PREFERENCES_OT_open_addon(bpy.types.Operator):
"""Tooltip"""
bl_idname = "preferences.rename_addon_search"
bl_label = "Open Addon preferences"
addon_name: bpy.props.StringProperty()
prefs_tabs: bpy.props.StringProperty()
def execute(self, context):
bpy.ops.screen.userpref_show()
bpy.context.preferences.active_section = 'ADDONS'
bpy.data.window_managers["WinMan"].addon_search = self.addon_name
prefs = context.preferences.addons[base_package].preferences
prefs.prefs_tabs = self.prefs_tabs
import addon_utils
mod = addon_utils.addons_fake_modules.get('collider_tools')
# mod is None the first time the operation is called :/
if mod:
mod.bl_info['show_expanded'] = True
# Find User Preferences area and redraw it
for window in bpy.context.window_manager.windows:
for area in window.screen.areas:
if area.type == 'USER_PREFERENCES':
area.tag_redraw()
bpy.ops.preferences.addon_expand(module=self.addon_name)
return {'FINISHED'}