def execute(self,context): bpy.ops.screen.userpref_show('INVOKE_AREA') context.user_preferences.active_section = "ADDONS" bpy.data.window_managers["WinMan"].addon_search = "MCprep" try: # if info["show_expanded"] != True: # #, where info comes from for mod, info in addons: # and addons is: # import addon_utils # addons = [(mod, addon_utils.module_bl_info(mod)) for mod in addon_utils.modules(refresh=False)] # # ie, get MCprep from mod in addon_utils.modules(refresh=False) # and then just grab # [addon_utils.module_bl_info(mod)] # less ideal way but works # for mod in # addon = addon_utils.module_bl_info(mode) import addon_utils addon = addon_utils.module_bl_info(__package__) if addon["show_expanded"] != True: print("not expanded, expanding?") bpy.ops.wm.addon_expand(module=__package__) except: if conf.v: print("Couldn't toggle MCprep preferences being expended") preferences_tab = self.tab # # just toggles not sets it, not helpful. need to SET it to expanded return {'FINISHED'}
def enable_addons(): """For now, enable all official addons, before extracting msgids.""" import addon_utils import bpy userpref = bpy.context.user_preferences used_ext = {ext.module for ext in userpref.addons} support = {"OFFICIAL"} # collect the categories that can be filtered on addons = [(mod, addon_utils.module_bl_info(mod)) for mod in addon_utils.modules(addon_utils.addons_fake_modules)] for mod, info in addons: module_name = mod.__name__ if module_name in used_ext or info["support"] not in support: continue print(" Enabling module ", module_name) bpy.ops.wm.addon_enable(module=module_name) # XXX There are currently some problems with bpy/rna... # *Very* tricky to solve! # So this is a hack to make all newly added operator visible by # bpy.types.OperatorProperties.__subclasses__() for cat in dir(bpy.ops): cat = getattr(bpy.ops, cat) for op in dir(cat): getattr(cat, op).get_rna()
def execute(self, _context): import addon_utils err_str = "" def err_cb(ex): import traceback nonlocal err_str err_str = traceback.format_exc() print(err_str) mod = addon_utils.enable(self.module, default_set=True, handle_error=err_cb) if mod: info = addon_utils.module_bl_info(mod) info_ver = info.get("blender", (0, 0, 0)) if info_ver > bpy.app.version: self.report( {'WARNING'}, "This script was written Blender " "version %d.%d.%d and might not " "function (correctly), " "though it is enabled" % info_ver ) return {'FINISHED'} else: if err_str: self.report({'ERROR'}, err_str) return {'CANCELLED'}
def execute(self, context): global lastError bpy.ops.addon_registry.update_database() installed_addons = {} for mod in addon_utils.modules(refresh=False): installed_addons[mod.__name__] = mod for name, addon in configuration["addons"].items(): info = addon["info"] available_version = info["version"] installed_addon = installed_addons.get(name, None) is_installed = bool(installed_addon) if is_installed: installed_info = addon_utils.module_bl_info(installed_addon) installed_version = list(installed_info["version"]) is_newer_available = is_newer_version(available_version, installed_version) if is_newer_available: lastError = install(name) if lastError == ERROR_EXTRACT_MANUALLY: return {"RUNNING_MODAL"} if lastError != ERROR_NONE: self.report({'ERROR'}, error_titles[lastError]) return {'CANCELLED'} addon_utils.modules(refresh=True) bpy.utils.refresh_script_paths() bpy.ops.script.reload() return {"FINISHED"}
def execute(self, _context): import addon_utils module_name = self.module mod = addon_utils.addons_fake_modules.get(module_name) if mod is not None: info = addon_utils.module_bl_info(mod) info["show_expanded"] = not info["show_expanded"] return {'FINISHED'}
def execute(self, context): module_name = self.module # unlikely to fail, module should have already been imported try: # mod = __import__(module_name) mod = USERPREF_PT_addons.module_get(module_name) except: import traceback traceback.print_exc() return {'CANCELLED'} info = addon_utils.module_bl_info(mod) info["show_expanded"] = not info["show_expanded"] return {'FINISHED'}
def addon_filter_items(self, context): import addon_utils items = [('All', "All", ""), ('Enabled', "Enabled", ""), ('Disabled', "Disabled", ""), ] items_unique = set() for mod in addon_utils.modules(addon_utils.addons_fake_modules): info = addon_utils.module_bl_info(mod) items_unique.add(info["category"]) items.extend([(cat, cat, "") for cat in sorted(items_unique)]) return items
def _init_addon_blacklist(): # in case we built without cycles if not bpy.app.build_options.cycles: BLACKLIST_ADDONS.add("cycles") # in case we built without freestyle if not bpy.app.build_options.freestyle: BLACKLIST_ADDONS.add("render_freestyle_svg") # netrender has known problems re-registering BLACKLIST_ADDONS.add("netrender") for mod in addon_utils.modules(): if addon_utils.module_bl_info(mod)['blender'] < (2, 80, 0): BLACKLIST_ADDONS.add(mod.__name__)
def execute(self, context): import addon_utils module_name = self.module _modules = addon_utils.modules(refresh=False) mod = addon_utils.addons_fake_modules.get(module_name) if mod is not None: info = addon_utils.module_bl_info(mod) info["show_expanded"] = True context.preferences.active_section = 'ADDONS' context.window_manager.addon_filter = 'All' context.window_manager.addon_search = info["name"] bpy.ops.screen.userpref_show('INVOKE_DEFAULT') return {'FINISHED'}
def addon_filter_items(self, context): import addon_utils items = [('All', "All", "All Add-ons"), ('User', "User", "All Add-ons Installed by User"), ('Enabled', "Enabled", "All Enabled Add-ons"), ('Disabled', "Disabled", "All Disabled Add-ons"), ] items_unique = set() for mod in addon_utils.modules(refresh=False): info = addon_utils.module_bl_info(mod) items_unique.add(info["category"]) items.extend([(cat, cat, "") for cat in sorted(items_unique)]) return items
def execute(self, context): mod = addon_utils.enable(self.module) if mod: info = addon_utils.module_bl_info(mod) info_ver = info.get("blender", (0, 0, 0)) if info_ver > bpy.app.version: self.report({'WARNING'}, ("This script was written Blender " "version %d.%d.%d and might not " "function (correctly).\n" "The script is enabled though.") % info_ver) return {'FINISHED'} else: return {'CANCELLED'}
def addon_filter_items(self, context): import addon_utils items = [("All", "All", "All Addons"), ("New Version Available", "New Version Available", "All New Version Available Addons"), ("Installed", "Installed", "All Installed Addons"), ("Not Installed", "Not Installed", "All Not Installed Addons") ] items_unique = set() for mod in addon_utils.modules(refresh=False): info = addon_utils.module_bl_info(mod) items_unique.add(info["category"]) items.extend([(cat, cat, "") for cat in sorted(items_unique)]) return items
def addon_filter_items(self, context): import addon_utils items = [ ('All', "All", "All Add-ons"), ('User', "User", "All Add-ons Installed by User"), ('Enabled', "Enabled", "All Enabled Add-ons"), ('Disabled', "Disabled", "All Disabled Add-ons"), ] items_unique = set() for mod in addon_utils.modules(refresh=False): info = addon_utils.module_bl_info(mod) items_unique.add(info["category"]) items.extend([(cat, cat, "") for cat in sorted(items_unique)]) return items
def addon_filter_items(self, context): import addon_utils items = [ ("All", "All", "All Addons"), ("New Version Available", "New Version Available", "All New Version Available Addons"), ("Installed", "Installed", "All Installed Addons"), ("Not Installed", "Not Installed", "All Not Installed Addons") ] items_unique = set() for mod in addon_utils.modules(refresh=False): info = addon_utils.module_bl_info(mod) items_unique.add(info["category"]) items.extend([(cat, cat, "") for cat in sorted(items_unique)]) return items
def execute(self, context): import addon_utils module_name = self.module _modules = addon_utils.modules(refresh=False) mod = addon_utils.addons_fake_modules.get(module_name) if mod is not None: info = addon_utils.module_bl_info(mod) info["show_expanded"] = True context.preferences.active_section = 'ADDONS' context.preferences.view.show_addons_enabled_only = False context.window_manager.addon_filter = 'All' context.window_manager.addon_search = info["name"] bpy.ops.screen.userpref_show('INVOKE_DEFAULT') return {'FINISHED'}
def build_addon_items_callback(self, context): global g_addon_cache global g_addon_cached_category props = get_panel_prop(context) if (g_addon_cache is None or g_addon_cached_category is None or g_addon_cached_category != props.category): items = [] for mod in addon_utils.modules(refresh=False): bl_info = addon_utils.module_bl_info(mod) if (not props.category or props.category == "All" or props.category == bl_info["category"]): items.append((mod.__file__, bl_info["name"], mod.__file__)) g_addon_cached_category = props.category g_addon_cache = tuple(sorted(items, key=lambda x: x[1].upper(), reverse=True)) return g_addon_cache
def draw(self, context): layout = self.layout # align just to pack more tightly col = layout.box().column(align=True) workspace = context.workspace userpref = context.user_preferences col.active = workspace.use_filter_by_owner import addon_utils addon_map = {mod.__name__: mod for mod in addon_utils.modules()} owner_ids = {owner_id.name for owner_id in workspace.owner_ids} for addon in userpref.addons: module_name = addon.module info = addon_utils.module_bl_info(addon_map[module_name]) if not info["use_owner"]: continue is_enabled = module_name in owner_ids row = col.row() row.operator( "wm.owner_disable" if is_enabled else "wm.owner_enable", icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT', text="", emboss=False, ).owner_id = module_name row.label(text="%s: %s" % (info["category"], info["name"])) if is_enabled: owner_ids.remove(module_name) # Detect unused if owner_ids: layout.label(text="Unknown add-ons", icon='ERROR') col = layout.box().column(align=True) for module_name in sorted(owner_ids): row = col.row() row.operator( "wm.owner_disable", icon='CHECKBOX_HLT', text="", emboss=False, ).owner_id = module_name row.label(text=module_name)
def draw(self, context): layout = self.layout """:type: bpy.types.UILayout""" column = layout.column() split = column.split(0.15) row = split.row() row.prop(self, 'show_all') row = split.row() row.operator('wm.addon_check_update', icon='FILE_REFRESH') row.prop(self, 'check_interval') row.prop(self, 'exclude_pattern') flow = column.column_flow(2) addons = context.user_preferences.addons if self.show_all: module_names = list(addons.keys()) else: module_names = [addon.module for addon in addons if addon.module in module_updated] def sort_func(name): if name in sys.modules: return addon_utils.module_bl_info(sys.modules[name])['name'] else: return name module_names.sort(key=sort_func) for module_name in module_names: if module_name == __name__: continue row = flow.row() if module_name in module_updated: icon = 'FILE_REFRESH' else: icon = 'NONE' if module_name in sys.modules: mod = sys.modules[module_name] name = addon_utils.module_bl_info(mod)['name'] else: name = module_name op = row.operator('wm.addon_reload', text=name, icon=icon) op.module = module_name
def draw(self, context): layout = self.layout # align just to pack more tightly col = layout.box().column(align=True) workspace = context.workspace prefs = context.preferences col.active = workspace.use_filter_by_owner import addon_utils addon_map = {mod.__name__: mod for mod in addon_utils.modules()} owner_ids = {owner_id.name for owner_id in workspace.owner_ids} for addon in prefs.addons: module_name = addon.module info = addon_utils.module_bl_info(addon_map[module_name]) if not info["use_owner"]: continue is_enabled = module_name in owner_ids row = col.row() row.operator( "wm.owner_disable" if is_enabled else "wm.owner_enable", icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT', text="", emboss=False, ).owner_id = module_name row.label(text="%s: %s" % (info["category"], info["name"])) if is_enabled: owner_ids.remove(module_name) # Detect unused if owner_ids: layout.label(text="Unknown add-ons", icon='ERROR') col = layout.box().column(align=True) for module_name in sorted(owner_ids): row = col.row() row.operator( "wm.owner_disable", icon='CHECKBOX_HLT', text="", emboss=False, ).owner_id = module_name row.label(text=module_name)
def _init_addon_blacklist(): # in case we built without cycles if not bpy.app.build_options.cycles: BLACKLIST_ADDONS.add("cycles") # in case we built without freestyle if not bpy.app.build_options.freestyle: BLACKLIST_ADDONS.add("render_freestyle_svg") # netrender has known problems re-registering BLACKLIST_ADDONS.add("netrender") if not bpy.app.build_options.xr_openxr: BLACKLIST_ADDONS.add("viewport_vr_preview") for mod in addon_utils.modules(): if addon_utils.module_bl_info(mod)['blender'] < (2, 80, 0): BLACKLIST_ADDONS.add(mod.__name__)
def execute(self, context): mod = addon_utils.enable(self.module) if hasattr(mod, '__name__'): info = addon_utils.module_bl_info(mod) info_ver = info.get("blender", (0, 0, 0)) if info_ver > bpy.app.version: self.report({'WARNING'}, ("This script was written Blender " "version %d.%d.%d and might not " "function (correctly).\n" "The script is enabled though.") % info_ver) return {'FINISHED'} else: msg = mod if type(mod) == str else "Error. See console" self.report({'ERROR'}, msg) return {'CANCELLED'}
def enum_addons(self, context): global _cached_enum_addons setts = getattr(self, "settings", settings.settings) if not _cached_enum_addons: for mod in addon_utils.modules(module_cache=addon_utils.addons_fake_modules): mod_info = addon_utils.module_bl_info(mod) # Skip OFFICIAL addons, they are already translated in main i18n system (together with Blender itself). if mod_info["support"] in {'OFFICIAL'}: continue src = mod.__file__ if src.endswith("__init__.py"): src = os.path.dirname(src) has_translation, _ = utils_i18n.I18n.check_py_module_has_translations(src, setts) name = mod_info["name"] if has_translation: name = name + " *" _cached_enum_addons.append((mod.__name__, name, mod_info["description"])) _cached_enum_addons.sort(key=lambda i: i[1]) return _cached_enum_addons
def execute(self, context): bpy.ops.screen.userpref_show('INVOKE_AREA') util.get_preferences(context).active_section = "ADDONS" bpy.data.window_managers["WinMan"].addon_search = "MCprep" addons_ids = [mod for mod in addon_utils.modules(refresh=False) if mod.__name__ == __package__] addon_blinfo = addon_utils.module_bl_info(addons_ids[0]) if not addon_blinfo["show_expanded"]: if hasattr(bpy.ops, "wm") and hasattr(bpy.ops.wm, "addon_expand"): # old 2.8 and 2.7 bpy.ops.wm.addon_expand(module=__package__) elif hasattr(bpy.ops, "preferences") and hasattr(bpy.ops.preferences, "addon_expand"): # later 2.8 buids bpy.ops.preferences.addon_expand(module=__package__) else: self.report({"INFO"}, "Navigate to the MCprep addon in preferences") addon_prefs = util.get_user_preferences(context) addon_prefs.preferences_tab = self.tab return {'FINISHED'}
def execute(self, context): mod = addon_utils.enable(self.module) if hasattr(mod,'__name__') : info = addon_utils.module_bl_info(mod) info_ver = info.get("blender", (0, 0, 0)) if info_ver > bpy.app.version: self.report({'WARNING'}, ("This script was written Blender " "version %d.%d.%d and might not " "function (correctly).\n" "The script is enabled though.") % info_ver) return {'FINISHED'} else: msg = mod if type(mod) == str else "Error. See console" self.report({'ERROR'}, msg) return {'CANCELLED'}
def enum_addons(self, context): global _cached_enum_addons setts = getattr(self, "settings", settings.settings) if not _cached_enum_addons: for mod in addon_utils.modules(addon_utils.addons_fake_modules): mod_info = addon_utils.module_bl_info(mod) # Skip OFFICIAL addons, they are already translated in main i18n system (together with Blender itself). if mod_info["support"] in {'OFFICIAL'}: continue src = mod.__file__ if src.endswith("__init__.py"): src = os.path.dirname(src) has_translation, _ = utils_i18n.I18n.check_py_module_has_translations(src, setts) name = mod_info["name"] if has_translation: name = name + " *" _cached_enum_addons.append((mod.__name__, name, mod_info["description"])) _cached_enum_addons.sort(key=lambda i: i[1]) return _cached_enum_addons
def execute(self, context): import addon_utils my_info = None for module in addon_utils.modules(): info = addon_utils.module_bl_info(module) if info['name'] == common.addon_name: my_info = info break area = common.get_request_area(context, 'USER_PREFERENCES') if area and my_info: context.user_preferences.active_section = 'ADDONS' context.window_manager.addon_search = my_info['name'] context.window_manager.addon_filter = 'All' if 'COMMUNITY' not in context.window_manager.addon_support: context.window_manager.addon_support = {'OFFICIAL', 'COMMUNITY'} if not my_info['show_expanded']: bpy.ops.wm.addon_expand(module=__name__.split('.')[0]) else: self.report(type={'ERROR'}, message="表示できるエリアが見つかりませんでした") return {'CANCELLED'} return {'FINISHED'}
def enable_addons(addons={}, support={}, disable=False): """ Enable (or disable) addons based either on a set of names, or a set of 'support' types. Returns the list of all affected addons (as fake modules)! """ import addon_utils userpref = bpy.context.user_preferences used_ext = {ext.module for ext in userpref.addons} ret = [ mod for mod in addon_utils.modules(addon_utils.addons_fake_modules) if ((addons and mod.__name__ in addons) or ( not addons and addon_utils.module_bl_info(mod)["support"] in support)) ] for mod in ret: module_name = mod.__name__ if disable: if module_name not in used_ext: continue print(" Disabling module ", module_name) bpy.ops.wm.addon_disable(module=module_name) else: if module_name in used_ext: continue print(" Enabling module ", module_name) bpy.ops.wm.addon_enable(module=module_name) # XXX There are currently some problems with bpy/rna... # *Very* tricky to solve! # So this is a hack to make all newly added operator visible by # bpy.types.OperatorProperties.__subclasses__() for cat in dir(bpy.ops): cat = getattr(bpy.ops, cat) for op in dir(cat): getattr(cat, op).get_rna() return ret
def execute(self, context): from .. import __name__ as main workspace = context.workspace prefs = context.preferences import addon_utils addon_map = {mod.__name__: mod for mod in addon_utils.modules()} owner_ids = {owner_id.name for owner_id in workspace.owner_ids} addons = list() for addon in prefs.addons: module_name = addon.module module = addon_map.get(module_name) if module is None: continue info = addon_utils.module_bl_info(module) if not info["use_owner"]: continue is_enabled = module_name in owner_ids if module_name == main: continue elif is_enabled: if self.down: addons.append(module_name) else: if not self.down: addons.append(module_name) for add in addons[::-1]: bpy.ops.preferences.addon_disable('INVOKE_DEFAULT', module=add) for add in addons: bpy.ops.preferences.addon_enable('INVOKE_DEFAULT', module=add) workspace.owner_ids.clear() return {'FINISHED'}
def get_addon(module_name): """ Gets a blender add-on :param module_name: The name of the add-on :type module_name: str :return: The add-on or None if the add-on could not be found :rtype: (bpy.types.Addon, module_bl_info) """ # noinspection PyUnresolvedReferences import addon_utils for module in addon_utils.modules(refresh=False): info = addon_utils.module_bl_info(module) if 'name' in info: name = info['name'] if name == module_name: return module, info return None
def enable_addons(addons={}, support={}, disable=False): """ Enable (or disable) addons based either on a set of names, or a set of 'support' types. Returns the list of all affected addons (as fake modules)! """ import addon_utils import bpy userpref = bpy.context.user_preferences used_ext = {ext.module for ext in userpref.addons} ret = [mod for mod in addon_utils.modules(addon_utils.addons_fake_modules) if ((addons and mod.__name__ in addons) or (not addons and addon_utils.module_bl_info(mod)["support"] in support))] for mod in ret: module_name = mod.__name__ if disable: if module_name not in used_ext: continue print(" Disabling module ", module_name) bpy.ops.wm.addon_disable(module=module_name) else: if module_name in used_ext: continue print(" Enabling module ", module_name) bpy.ops.wm.addon_enable(module=module_name) # XXX There are currently some problems with bpy/rna... # *Very* tricky to solve! # So this is a hack to make all newly added operator visible by # bpy.types.OperatorProperties.__subclasses__() for cat in dir(bpy.ops): cat = getattr(bpy.ops, cat) for op in dir(cat): getattr(cat, op).get_rna() return ret
def execute(self, context): import addon_utils my_info = None for module in addon_utils.modules(): info = addon_utils.module_bl_info(module) if info['name'] == common.addon_name: my_info = info break area = common.get_request_area(context, 'USER_PREFERENCES') if area and my_info: context.user_preferences.active_section = 'ADDONS' context.window_manager.addon_search = my_info['name'] context.window_manager.addon_filter = 'All' if 'COMMUNITY' not in context.window_manager.addon_support: context.window_manager.addon_support = { 'OFFICIAL', 'COMMUNITY' } if not my_info['show_expanded']: bpy.ops.wm.addon_expand(module=__name__.split('.')[0]) else: self.report(type={'ERROR'}, message="表示できるエリアが見つかりませんでした") return {'CANCELLED'} return {'FINISHED'}
def execute(self, context): bpy.ops.screen.userpref_show('INVOKE_AREA') util.get_preferences(context).active_section = "ADDONS" bpy.data.window_managers["WinMan"].addon_search = "MCprep" addons_ids = [ mod for mod in addon_utils.modules(refresh=False) if mod.__name__ == __package__ ] addon_blinfo = addon_utils.module_bl_info(addons_ids[0]) if not addon_blinfo["show_expanded"]: if hasattr(bpy.ops, "wm") and hasattr( bpy.ops.wm, "addon_expand"): # old 2.8 and 2.7 bpy.ops.wm.addon_expand(module=__package__) elif hasattr(bpy.ops, "preferences") and hasattr( bpy.ops.preferences, "addon_expand"): # later 2.8 buids bpy.ops.preferences.addon_expand(module=__package__) else: self.report({"INFO"}, "Navigate to the MCprep addon in preferences") addon_prefs = util.get_user_preferences(context) addon_prefs.preferences_tab = self.tab return {'FINISHED'}
def sort_func(name): if name in sys.modules: return addon_utils.module_bl_info(sys.modules[name])['name'] else: return name
def execute(self, context): import addon_utils import traceback import zipfile import shutil import os pyfile = self.filepath if self.target == 'DEFAULT': # don't use bpy.utils.script_paths("addons") because we may not be able to write to it. path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True) else: path_addons = context.preferences.filepaths.script_directory if path_addons: path_addons = os.path.join(path_addons, "addons") if not path_addons: self.report({'ERROR'}, "Failed to get add-ons path") return {'CANCELLED'} if not os.path.isdir(path_addons): try: os.makedirs(path_addons, exist_ok=True) except: traceback.print_exc() # Check if we are installing from a target path, # doing so causes 2+ addons of same name or when the same from/to # location is used, removal of the file! addon_path = "" pyfile_dir = os.path.dirname(pyfile) for addon_path in addon_utils.paths(): if os.path.samefile(pyfile_dir, addon_path): self.report({'ERROR'}, "Source file is in the add-on search path: %r" % addon_path) return {'CANCELLED'} del addon_path del pyfile_dir # done checking for exceptional case addons_old = {mod.__name__ for mod in addon_utils.modules()} # check to see if the file is in compressed format (.zip) if zipfile.is_zipfile(pyfile): try: file_to_extract = zipfile.ZipFile(pyfile, 'r') except: traceback.print_exc() return {'CANCELLED'} if self.overwrite: for f in file_to_extract.namelist(): module_filesystem_remove(path_addons, f) else: for f in file_to_extract.namelist(): path_dest = os.path.join(path_addons, os.path.basename(f)) if os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} try: # extract the file to "addons" file_to_extract.extractall(path_addons) except: traceback.print_exc() return {'CANCELLED'} else: path_dest = os.path.join(path_addons, os.path.basename(pyfile)) if self.overwrite: module_filesystem_remove(path_addons, os.path.basename(pyfile)) elif os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} # if not compressed file just copy into the addon path try: shutil.copyfile(pyfile, path_dest) except: traceback.print_exc() return {'CANCELLED'} addons_new = {mod.__name__ for mod in addon_utils.modules()} - addons_old addons_new.discard("modules") # disable any addons we may have enabled previously and removed. # this is unlikely but do just in case. bug [#23978] for new_addon in addons_new: addon_utils.disable(new_addon, default_set=True) # possible the zip contains multiple addons, we could disallow this # but for now just use the first for mod in addon_utils.modules(refresh=False): if mod.__name__ in addons_new: info = addon_utils.module_bl_info(mod) # show the newly installed addon. context.window_manager.addon_filter = 'All' context.window_manager.addon_search = info["name"] break # in case a new module path was created to install this addon. bpy.utils.refresh_script_paths() # print message msg = ( tip_("Modules Installed (%s) from %r into %r") % (", ".join(sorted(addons_new)), pyfile, path_addons) ) print(msg) self.report({'INFO'}, msg) return {'FINISHED'}
def draw(self, context): import addon_utils layout = self.layout userpref = context.user_preferences used_ext = {ext.module for ext in userpref.addons} userpref_addons_folder = os.path.join( userpref.filepaths.script_directory, "addons") scripts_addons_folder = bpy.utils.user_resource('SCRIPTS', "addons") # collect the categories that can be filtered on addons = [ (mod, addon_utils.module_bl_info(mod)) for mod in addon_utils.modules(addon_utils.addons_fake_modules) ] split = layout.split(percentage=0.2) col = split.column() col.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM') col.label(text="Supported Level") col.prop(context.window_manager, "addon_support", expand=True) col.label(text="Categories") col.prop(context.window_manager, "addon_filter", expand=True) col = split.column() # set in addon_utils.modules(...) if addon_utils.error_duplicates: self.draw_error( col, "Multiple addons using the same name found!\n" "likely a problem with the script search path.\n" "(see console for details)", ) if addon_utils.error_encoding: self.draw_error( col, "One or more addons do not have UTF-8 encoding\n" "(see console for details)", ) filter = context.window_manager.addon_filter search = context.window_manager.addon_search.lower() support = context.window_manager.addon_support # initialized on demand user_addon_paths = [] for mod, info in addons: module_name = mod.__name__ is_enabled = module_name in used_ext if info["support"] not in support: continue # check if addon should be visible with current filters if ((filter == "All") or (filter == info["category"]) or (filter == "Enabled" and is_enabled) or (filter == "Disabled" and not is_enabled) or (filter == "User" and (mod.__file__.startswith( (scripts_addons_folder, userpref_addons_folder))))): if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): continue else: continue # Addon UI Code box = col.column().box() colsub = box.column() row = colsub.row() row.operator("wm.addon_expand", icon='TRIA_DOWN' if info["show_expanded"] else 'TRIA_RIGHT', emboss=False).module = module_name rowsub = row.row() rowsub.active = is_enabled rowsub.label(text='%s: %s' % (info["category"], info["name"])) if info["warning"]: rowsub.label(icon='ERROR') # icon showing support level. rowsub.label(icon=self._support_icon_mapping.get( info["support"], 'QUESTION')) if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name # Expanded UI (only if additional info is available) if info["show_expanded"]: if info["description"]: split = colsub.row().split(percentage=0.15) split.label(text="Description:") split.label(text=info["description"]) if info["location"]: split = colsub.row().split(percentage=0.15) split.label(text="Location:") split.label(text=info["location"]) if mod: split = colsub.row().split(percentage=0.15) split.label(text="File:") split.label(text=mod.__file__) if info["author"]: split = colsub.row().split(percentage=0.15) split.label(text="Author:") split.label(text=info["author"]) if info["version"]: split = colsub.row().split(percentage=0.15) split.label(text="Version:") split.label(text='.'.join( str(x) for x in info["version"])) if info["warning"]: split = colsub.row().split(percentage=0.15) split.label(text="Warning:") split.label(text=' ' + info["warning"], icon='ERROR') user_addon = USERPREF_PT_addons.is_user_addon( mod, user_addon_paths) tot_row = bool(info["wiki_url"]) + bool( info["tracker_url"]) + bool(user_addon) if tot_row: split = colsub.row().split(percentage=0.15) split.label(text="Internet:") if info["wiki_url"]: split.operator("wm.url_open", text="Link to the Wiki", icon='HELP').url = info["wiki_url"] if info["tracker_url"]: split.operator( "wm.url_open", text="Report a Bug", icon='URL').url = info["tracker_url"] if user_addon: split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__ for i in range(4 - tot_row): split.separator() # Append missing scripts # First collect scripts that are used but have no script file. module_names = {mod.__name__ for mod, info in addons} missing_modules = {ext for ext in used_ext if ext not in module_names} if missing_modules and filter in {"All", "Enabled"}: col.column().separator() col.column().label(text="Missing script files") module_names = {mod.__name__ for mod, info in addons} for module_name in sorted(missing_modules): is_enabled = module_name in used_ext # Addon UI Code box = col.column().box() colsub = box.column() row = colsub.row() row.label(text=module_name, icon='ERROR') if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name
def draw(self, context): layout = self.layout userpref = context.user_preferences used_ext = {ext.module for ext in userpref.addons} # collect the categories that can be filtered on addons = [(mod, addon_utils.module_bl_info(mod)) for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules)] split = layout.split(percentage=0.2) col = split.column() col.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM') col.label(text="Categories") col.prop(context.window_manager, "addon_filter", expand=True) col.label(text="Supported Level") col.prop(context.window_manager, "addon_support", expand=True) col = split.column() # set in addon_utils.modules(...) if addon_utils.error_duplicates: self.draw_error(col, "Multiple addons using the same name found!\n" "likely a problem with the script search path.\n" "(see console for details)", ) if addon_utils.error_encoding: self.draw_error(col, "One or more addons do not have UTF-8 encoding\n" "(see console for details)", ) filter = context.window_manager.addon_filter search = context.window_manager.addon_search.lower() support = context.window_manager.addon_support # initialized on demand user_addon_paths = [] for mod, info in addons: module_name = mod.__name__ is_enabled = module_name in used_ext if info["support"] not in support: continue # check if add-on should be visible with current filters if (filter == "All") or \ (filter == info["category"]) or \ (filter == "Enabled" and is_enabled) or \ (filter == "Disabled" and not is_enabled): if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): continue else: continue # Addon UI Code box = col.column().box() colsub = box.column() row = colsub.row() row.operator("wm.addon_expand", icon='TRIA_DOWN' if info["show_expanded"] else 'TRIA_RIGHT', emboss=False).module = module_name rowsub = row.row() rowsub.active = is_enabled rowsub.label(text='%s: %s' % (info['category'], info["name"])) if info["warning"]: rowsub.label(icon='ERROR') # icon showing support level. if info["support"] == 'OFFICIAL': rowsub.label(icon='FILE_BLEND') elif info["support"] == 'COMMUNITY': rowsub.label(icon='POSE_DATA') else: rowsub.label(icon='QUESTION') if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name # Expanded UI (only if additional infos are available) if info["show_expanded"]: if info["description"]: split = colsub.row().split(percentage=0.15) split.label(text='Description:') split.label(text=info["description"]) if info["location"]: split = colsub.row().split(percentage=0.15) split.label(text='Location:') split.label(text=info["location"]) if info["author"]: split = colsub.row().split(percentage=0.15) split.label(text='Author:') split.label(text=info["author"]) if info["version"]: split = colsub.row().split(percentage=0.15) split.label(text='Version:') split.label(text='.'.join(str(x) for x in info["version"])) if info["warning"]: split = colsub.row().split(percentage=0.15) split.label(text="Warning:") split.label(text=' ' + info["warning"], icon='ERROR') user_addon = USERPREF_PT_addons.is_user_addon(mod, user_addon_paths) tot_row = bool(info["wiki_url"]) + bool(info["tracker_url"]) + bool(user_addon) if tot_row: split = colsub.row().split(percentage=0.15) split.label(text="Internet:") if info["wiki_url"]: split.operator("wm.url_open", text="Link to the Wiki", icon='HELP').url = info["wiki_url"] if info["tracker_url"]: split.operator("wm.url_open", text="Report a Bug", icon='URL').url = info["tracker_url"] if user_addon: split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__ for i in range(4 - tot_row): split.separator() # Append missing scripts # First collect scripts that are used but have no script file. module_names = {mod.__name__ for mod, info in addons} missing_modules = {ext for ext in used_ext if ext not in module_names} if missing_modules and filter in {"All", "Enabled"}: col.column().separator() col.column().label(text="Missing script files") module_names = {mod.__name__ for mod, info in addons} for module_name in sorted(missing_modules): is_enabled = module_name in used_ext # Addon UI Code box = col.column().box() colsub = box.column() row = colsub.row() row.label(text=module_name, icon='ERROR') if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name
def execute(self, context): import traceback import zipfile import shutil pyfile = self.filepath if self.target == 'DEFAULT': # dont use bpy.utils.script_paths("addons") because we may not be able to write to it. path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True) else: path_addons = bpy.context.user_preferences.filepaths.script_directory if path_addons: path_addons = os.path.join(path_addons, "addons") if not path_addons: self.report({'ERROR'}, "Failed to get addons path") return {'CANCELLED'} # create dir is if missing. if not os.path.exists(path_addons): os.makedirs(path_addons) # Check if we are installing from a target path, # doing so causes 2+ addons of same name or when the same from/to # location is used, removal of the file! addon_path = "" pyfile_dir = os.path.dirname(pyfile) for addon_path in addon_utils.paths(): if os.path.samefile(pyfile_dir, addon_path): self.report({'ERROR'}, "Source file is in the addon search path: %r" % addon_path) return {'CANCELLED'} del addon_path del pyfile_dir # done checking for exceptional case addons_old = { mod.__name__ for mod in addon_utils.modules( USERPREF_PT_addons._addons_fake_modules) } #check to see if the file is in compressed format (.zip) if zipfile.is_zipfile(pyfile): try: file_to_extract = zipfile.ZipFile(pyfile, 'r') except: traceback.print_exc() return {'CANCELLED'} if self.overwrite: for f in file_to_extract.namelist(): WM_OT_addon_install._module_remove(path_addons, f) else: for f in file_to_extract.namelist(): path_dest = os.path.join(path_addons, os.path.basename(f)) if os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} try: # extract the file to "addons" file_to_extract.extractall(path_addons) # zip files can create this dir with metadata, don't need it macosx_dir = os.path.join(path_addons, '__MACOSX') if os.path.isdir(macosx_dir): shutil.rmtree(macosx_dir) except: traceback.print_exc() return {'CANCELLED'} else: path_dest = os.path.join(path_addons, os.path.basename(pyfile)) if self.overwrite: WM_OT_addon_install._module_remove(path_addons, os.path.basename(pyfile)) elif os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} #if not compressed file just copy into the addon path try: shutil.copyfile(pyfile, path_dest) except: traceback.print_exc() return {'CANCELLED'} addons_new = { mod.__name__ for mod in addon_utils.modules( USERPREF_PT_addons._addons_fake_modules) } - addons_old addons_new.discard("modules") # disable any addons we may have enabled previously and removed. # this is unlikely but do just incase. bug [#23978] for new_addon in addons_new: addon_utils.disable(new_addon) # possible the zip contains multiple addons, we could disallow this # but for now just use the first for mod in addon_utils.modules( USERPREF_PT_addons._addons_fake_modules): if mod.__name__ in addons_new: info = addon_utils.module_bl_info(mod) # show the newly installed addon. context.window_manager.addon_filter = 'All' context.window_manager.addon_search = info["name"] break # incase a new module path was created to install this addon. bpy.utils.refresh_script_paths() # TODO, should not be a warning. # self.report({'WARNING'}, "File installed to '%s'\n" % path_dest) return {'FINISHED'}
def execute(self, context): import traceback import zipfile import shutil pyfile = self.filepath if self.target == 'DEFAULT': # dont use bpy.utils.script_paths("addons") because we may not be able to write to it. path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True) else: path_addons = bpy.context.user_preferences.filepaths.script_directory if path_addons: path_addons = os.path.join(path_addons, "addons") if not path_addons: self.report({'ERROR'}, "Failed to get addons path") return {'CANCELLED'} # create dir is if missing. if not os.path.exists(path_addons): os.makedirs(path_addons) # Check if we are installing from a target path, # doing so causes 2+ addons of same name or when the same from/to # location is used, removal of the file! addon_path = "" pyfile_dir = os.path.dirname(pyfile) for addon_path in addon_utils.paths(): if os.path.samefile(pyfile_dir, addon_path): self.report({'ERROR'}, "Source file is in the addon search path: %r" % addon_path) return {'CANCELLED'} del addon_path del pyfile_dir # done checking for exceptional case addons_old = {mod.__name__ for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules)} #check to see if the file is in compressed format (.zip) if zipfile.is_zipfile(pyfile): try: file_to_extract = zipfile.ZipFile(pyfile, 'r') except: traceback.print_exc() return {'CANCELLED'} if self.overwrite: for f in file_to_extract.namelist(): WM_OT_addon_install._module_remove(path_addons, f) else: for f in file_to_extract.namelist(): path_dest = os.path.join(path_addons, os.path.basename(f)) if os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} try: # extract the file to "addons" file_to_extract.extractall(path_addons) # zip files can create this dir with metadata, don't need it macosx_dir = os.path.join(path_addons, '__MACOSX') if os.path.isdir(macosx_dir): shutil.rmtree(macosx_dir) except: traceback.print_exc() return {'CANCELLED'} else: path_dest = os.path.join(path_addons, os.path.basename(pyfile)) if self.overwrite: WM_OT_addon_install._module_remove(path_addons, os.path.basename(pyfile)) elif os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} #if not compressed file just copy into the addon path try: shutil.copyfile(pyfile, path_dest) except: traceback.print_exc() return {'CANCELLED'} addons_new = {mod.__name__ for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules)} - addons_old addons_new.discard("modules") # disable any addons we may have enabled previously and removed. # this is unlikely but do just incase. bug [#23978] for new_addon in addons_new: addon_utils.disable(new_addon) # possible the zip contains multiple addons, we could disallow this # but for now just use the first for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules): if mod.__name__ in addons_new: info = addon_utils.module_bl_info(mod) # show the newly installed addon. context.window_manager.addon_filter = 'All' context.window_manager.addon_search = info["name"] break # incase a new module path was created to install this addon. bpy.utils.refresh_script_paths() # TODO, should not be a warning. # self.report({'WARNING'}, "File installed to '%s'\n" % path_dest) return {'FINISHED'}
def draw(self, context): import os import addon_utils userpref = context.user_preferences used_ext = {ext.module for ext in userpref.addons} userpref_addons_folder = os.path.join(userpref.filepaths.script_directory, "addons") scripts_addons_folder = bpy.utils.user_resource('SCRIPTS', "addons") #collect the categories that can be filtered on addons = [(mod, addon_utils.module_bl_info(mod)) for mod in addon_utils.modules(refresh=True)] #Management header layout layout = self.layout layout.label("Run Blender as admin for full permission",icon='LAYER_USED') split = layout.split(percentage=0.60, align=True,) if bpy.data.window_managers["WinMan"].addon_filter == 'Favourites': split.operator("wm.check_fav", icon='SPACE2',text="Favourites") else: split.operator("wm.check_fav", icon='SPACE3',text="Favourites") split.operator("wm.user_adon", text="User") split.operator("wm.ena_adon", icon='SAVE_AS',text="") split.operator("wm.all_adon", icon='BOOKMARKS',text="") #searche layout layout = self.layout layout.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM') row = layout.row() split = layout.split() col = split.column() filter = context.window_manager.addon_filter search = context.window_manager.addon_search.lower() support = context.window_manager.addon_support #initialized on demand user_addon_paths = [] addon_numb = 0 for mod, info in addons: module_name = mod.__name__ module_realpath = mod.__file__ is_enabled = module_name in used_ext if info["support"] not in support: continue #serche parmetres if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): continue else: continue # check if addon should be visible with current filters if ((filter == "All") or (filter == info["category"]) or (filter == "Enabled" and is_enabled) or (filter == "Disabled" and not is_enabled) or (filter == "User" and (mod.__file__.startswith((scripts_addons_folder, userpref_addons_folder)))) ): #limit visible addon on 'All' folder if bpy.data.window_managers["WinMan"].addon_filter == 'All' and addon_numb < 10: # Addon UI Code col_box = col.column() box = col_box.box() colsub = box.column() row = colsub.row() if info["category"] == "Favourites": row.operator("wm.un_chemin", icon='PINNED',emboss=False,text="").chemin = module_realpath sub = row.row() sub.label(info["name"], icon='SMALL_TRI_RIGHT_VEC') else: row.operator("wm.get_chemin", icon='UNPINNED',emboss=False,text="").chemin = module_realpath sub = row.row() sub.label(info["name"],) sub.operator("wm.addon_remove", text="", icon='PANEL_CLOSE',emboss=False).module = mod.__name__ if is_enabled: row.operator("wm.addon_disable", icon='FILE_TICK', text="", emboss=False).module = module_name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name #incrementation for limitation addon_numb +=1 if bpy.data.window_managers["WinMan"].addon_filter != 'All': # Addon UI Code col_box = col.column() box = col_box.box() colsub = box.column() row = colsub.row() if info["category"] == "Favourites": row.operator("wm.un_chemin", icon='PINNED',emboss=False,text="").chemin = module_realpath sub = row.row() sub.label(info["name"], icon='SMALL_TRI_RIGHT_VEC') else: row.operator("wm.get_chemin", icon='UNPINNED',emboss=False,text="").chemin = module_realpath sub = row.row() sub.label(info["name"],) sub.operator("wm.addon_remove", text="", icon='PANEL_CLOSE',emboss=False).module = mod.__name__ if is_enabled: row.operator("wm.addon_disable", icon='FILE_TICK', text="", emboss=False).module = module_name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name
def draw(self, context): layout = self.layout userpref = context.user_preferences used_ext = {ext.module for ext in userpref.addons} # collect the categories that can be filtered on addons = [ (mod, addon_utils.module_bl_info(mod)) for mod in addon_utils.modules(addon_utils.addons_fake_modules) ] split = layout.split(percentage=0.2) col = split.column() col.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM') col.label(text="Categories") col.prop(context.window_manager, "addon_filter", expand=True) col.label(text="Supported Level") col.prop(context.window_manager, "addon_support", expand=True) col = split.column() # set in addon_utils.modules(...) if addon_utils.error_duplicates: self.draw_error( col, "Multiple addons using the same name found!\n" "likely a problem with the script search path.\n" "(see console for details)", ) if addon_utils.error_encoding: self.draw_error( col, "One or more addons do not have UTF-8 encoding\n" "(see console for details)", ) filter = context.window_manager.addon_filter search = context.window_manager.addon_search.lower() support = context.window_manager.addon_support # initialized on demand user_addon_paths = [] for mod, info in addons: module_name = mod.__name__ is_enabled = module_name in used_ext if info["support"] not in support: continue # check if add-on should be visible with current filters if (filter == "All") or \ (filter == info["category"]) or \ (filter == "Enabled" and is_enabled) or \ (filter == "Disabled" and not is_enabled): if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): continue else: continue # Addon UI Code box = col.column().box() colsub = box.column() row = colsub.row() row.operator("wm.addon_expand", icon='TRIA_DOWN' if info["show_expanded"] else 'TRIA_RIGHT', emboss=False).module = module_name rowsub = row.row() rowsub.active = is_enabled rowsub.label(text='%s: %s' % (info['category'], info["name"])) if info["warning"]: rowsub.label(icon='ERROR') # icon showing depedencies (child or parent). disable_check = module_name if info["dependencies"]: rowsub.label(icon='LINKED') # icon showing support level. if info["support"] == 'OFFICIAL': rowsub.label(icon='FILE_BLEND') elif info["support"] == 'COMMUNITY': rowsub.label(icon='POSE_DATA') else: rowsub.label(icon='QUESTION') if info["childs"] and is_enabled: row.label(icon='LINKED') elif is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name # Expanded UI (only if additional infos are available) if info["show_expanded"]: if info["description"]: split = colsub.row().split(percentage=0.15) split.label(text="Description:") split.label(text=info["description"]) if info["location"]: split = colsub.row().split(percentage=0.15) split.label(text="Location:") split.label(text=info["location"]) if info["author"]: split = colsub.row().split(percentage=0.15) split.label(text="Author:") split.label(text=info["author"]) if info["version"]: split = colsub.row().split(percentage=0.15) split.label(text="Version:") split.label(text='.'.join( str(x) for x in info["version"])) if info["dependencies"]: split = colsub.row().split(percentage=0.15) split.label(text='Dependencies:') parent_list, msg = addon_utils.parent_list( info["dependencies"]) if parent_list: txt = '' for n, v in parent_list: txt += '%s v%s, ' % (n, '.'.join( str(x) for x in v)) else: txt = msg split.label(text=txt[:-2]) if info["childs"]: split = colsub.row().split(percentage=0.15) split.label(text='In use by:') txt = '' for n in info["childs"]: txt += '%s, ' % (n) split.label(text=txt[:-2]) if info["warning"]: split = colsub.row().split(percentage=0.15) split.label(text="Warning:") split.label(text=' ' + info["warning"], icon='ERROR') user_addon = USERPREF_PT_addons.is_user_addon( mod, user_addon_paths) tot_row = bool(info["wiki_url"]) + bool( info["tracker_url"]) + bool(user_addon) if tot_row: split = colsub.row().split(percentage=0.15) split.label(text="Internet:") if info["wiki_url"]: split.operator("wm.url_open", text="Link to the Wiki", icon='HELP').url = info["wiki_url"] if info["tracker_url"]: split.operator( "wm.url_open", text="Report a Bug", icon='URL').url = info["tracker_url"] if user_addon: split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__ for i in range(4 - tot_row): split.separator() # Append missing scripts # First collect scripts that are used but have no script file. module_names = {mod.__name__ for mod, info in addons} missing_modules = {ext for ext in used_ext if ext not in module_names} if missing_modules and filter in {"All", "Enabled"}: col.column().separator() col.column().label(text="Missing script files") module_names = {mod.__name__ for mod, info in addons} for module_name in sorted(missing_modules): is_enabled = module_name in used_ext # Addon UI Code box = col.column().box() colsub = box.column() row = colsub.row() row.label(text=module_name, icon='ERROR') if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name
import sys import os BLACKLIST = { "bl_i18n_utils", "bl_previews_utils", "cycles", "io_export_dxf", # TODO, check on why this fails 'io_import_dxf', # Because of cydxfentity.so dependency # The unpacked wheel is only loaded when actually used, not directly on import: os.path.join("io_blend_utils", "blender_bam-unpacked.whl"), } for mod in addon_utils.modules(): if addon_utils.module_bl_info(mod)['blender'] < (2, 80, 0): BLACKLIST.add(mod.__name__) # Some modules need to add to the `sys.path`. MODULE_SYS_PATHS = { # Runs in a Python subprocess, so its expected its basedir can be imported. "io_blend_utils.blendfile_pack": ".", } if not bpy.app.build_options.freestyle: BLACKLIST.add("render_freestyle_svg") BLACKLIST_DIRS = (os.path.join(bpy.utils.resource_path('USER'), "scripts"), ) + tuple(addon_utils.paths()[1:])
def dump_addon_messages(module_name, do_checks, settings): import addon_utils # Get current addon state (loaded or not): was_loaded = addon_utils.check(module_name)[1] # Enable our addon. addon = utils.enable_addons(addons={module_name})[0] addon_info = addon_utils.module_bl_info(addon) ver = addon_info["name"] + " " + ".".join(str(v) for v in addon_info["version"]) rev = 0 date = datetime.datetime.now() pot = utils.I18nMessages.gen_empty_messages(settings.PARSER_TEMPLATE_ID, ver, rev, date, date.year, settings=settings) msgs = pot.msgs minus_pot = utils.I18nMessages.gen_empty_messages(settings.PARSER_TEMPLATE_ID, ver, rev, date, date.year, settings=settings) minus_msgs = minus_pot.msgs check_ctxt = _gen_check_ctxt(settings) if do_checks else None minus_check_ctxt = _gen_check_ctxt(settings) if do_checks else None # Get strings from RNA, our addon being enabled. print("A") reports = _gen_reports(check_ctxt) print("B") dump_rna_messages(msgs, reports, settings) print("C") # Now disable our addon, and rescan RNA. utils.enable_addons(addons={module_name}, disable=True) print("D") reports["check_ctxt"] = minus_check_ctxt print("E") dump_rna_messages(minus_msgs, reports, settings) print("F") # Restore previous state if needed! if was_loaded: utils.enable_addons(addons={module_name}) # and make the diff! for key in minus_msgs: if key != settings.PO_HEADER_KEY: del msgs[key] if check_ctxt: _diff_check_ctxt(check_ctxt, minus_check_ctxt) # and we are done with those! del minus_pot del minus_msgs del minus_check_ctxt # get strings from UI layout definitions text="..." args reports["check_ctxt"] = check_ctxt dump_py_messages(msgs, reports, {addon}, settings, addons_only=True) pot.unescape() # Strings gathered in py/C source code may contain escaped chars... print_info(reports, pot) print("Finished extracting UI messages!") return pot
def draw(self, context): layout = self.layout if lastError != ERROR_NONE: box = layout.box() box.label(icon='ERROR', text=error_titles[lastError]) if lastError == ERROR_EXTRACT_MANUALLY: box.label( text= "The downloaded file is not recognized. It should be an archive that you need to extract manually." ) split = box.split(factor=0.6) split.label( text= "By installing 7-Zip and adding it to your PATH, the registry recognizes more formats." ) row = split.row() row.operator("wm.url_open", icon='URL', text="Download 7-Zip" ).url = "http://www.7-zip.org/download.html" row.operator("wm.url_open", icon='URL', text="Installation instructions" ).url = "http://www.7-zip.org/download.html" elif lastError == ERROR_FAILED_COPY: box.label(text="The addon file is unreachable.") elif lastError == ERROR_FAILED_DOWNLOAD: box.label( text= "Something may be wrong with your Internet connection. Please try again later." ) elif lastError == ERROR_FAILED_REQUEST: box.label( text= "The server hosting the addon may be down. Please try again later." ) box.label( text= "The addon may have moved to another URL. If you think this is the case, please report it using the following button, so that the maintainer will update the registry." ) elif lastError == ERROR_FAILED_RETRIEVE_ADDON_LIST: box.label( text= "The registry server may be down. Please try again later.") box.label( text= "The registry may have moved to another URL. If you think this is the case, please report it using the following button, so that the maintainer will update the registry." ) elif lastError == ERROR_HASH_MISMATCH: box.label( text= "The downloaded addon does not match the registry record. For security reasons, it won't be installed." ) box.label( text= "It could mean that the addon's author has uploaded a new version with the same URL." ) box.label( text= "If you think this is the case, please report it using the following button, so that the maintainer will update the registry." ) elif lastError == ERROR_NO_HASH: box.label( text= "The registry record does not contain an expected hash, therefore the addon authenticity can't be verified." ) box.label( text= "You may be using an unofficial registry. If this is the case, please report it to its maintainers." ) split = box.split(factor=0.9) split.operator( "wm.url_open", icon='URL', text= "If the error persists, please report an issue to the registry maintainers" ).url = "https://github.com/Bloutiouf/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/issues/new" split.operator("addon_registry.hide_error", icon='X') addon_dir = get_addon_dir() userpref = context.preferences wm = bpy.context.window_manager installed_addons = {} for mod in addon_utils.modules(refresh=False): installed_addons[mod.__name__] = mod enabled_addon_names = {addon.module for addon in userpref.addons} split = layout.split(factor=0.2) col = split.column() col.operator(UpdateDatabase.bl_idname, icon='FILE_REFRESH') col.separator() col.prop(wm, "addon_registry_search", text="", icon='VIEWZOOM') col.label(text="Categories") col.prop(wm, "addon_registry_filter", expand=True) col.separator() col.operator(ResetConfiguration.bl_idname, icon='CANCEL') col = split.column() filter = wm.addon_registry_filter search = wm.addon_registry_search.lower() for name, addon in sorted_addons: info = addon["info"] available_version = info["version"] show_expanded = addon.get("show_expanded", False) installed_addon = installed_addons.get(name, None) installed_version = None is_installed = bool(installed_addon) is_newer_available = False is_enabled = False if is_installed: installed_info = addon_utils.module_bl_info(installed_addon) installed_version = list(installed_info["version"]) is_newer_available = is_newer_version(available_version, installed_version) is_enabled = name in enabled_addon_names if ((filter == "All") or (filter == "New Version Available" and is_newer_available) or (filter == info["category"]) or (filter == "Installed" and is_installed) or (filter == "Not Installed" and not is_installed)): if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): continue else: continue peers = addon.get("peers", None) if peers and (type(peers) is not list or len(peers) == 0): peers = None warning = info.get("warning", None) col_box = col.column() box = col_box.box() colsub = box.column() row = colsub.row() row.operator( Expand.bl_idname, icon='TRIA_DOWN' if show_expanded else "TRIA_RIGHT", emboss=False).addon_name = name sub = row.split(factor=0.6) text = sub.row() text.label(text="%s: %s" % (info["category"], info["name"])) if peers: text.label(icon='LINK_AREA') if warning: text.label(icon='ERROR') buttons = sub.split(factor=0.5) if is_installed: buttons.operator("preferences.addon_remove", text=".".join(map(str, installed_version)), icon='CANCEL').module = name else: buttons.label(text="Not installed") if is_installed and not is_newer_available: buttons.label(text="Latest version") else: buttons.operator(Install.bl_idname, text=".".join(map(str, available_version)), icon='WORLD').addon_name = name if is_installed: if is_enabled: row.operator("preferences.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = name else: row.operator("preferences.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = name else: sub = row.row() sub.active = False sub.label(icon='CHECKBOX_DEHLT', text="") if show_expanded: if peers: colsub.row().label( icon='LINK_AREA', text="Bundled with: " + ", ".join( configuration["addons"][peer]["info"]["name"] for peer in peers)) if info["description"]: split = colsub.row().split(factor=0.15) split.label(text="Description:") split.label(text=info["description"]) if info["location"]: split = colsub.row().split(factor=0.15) split.label(text="Location:") split.label(text=info["location"]) if info["author"]: split = colsub.row().split(factor=0.15) split.label(text="Author:") split.label(text=info["author"], translate=False) if info["version"]: split = colsub.row().split(factor=0.15) split.label(text="Version:") split.label(text=".".join( str(x) for x in info["version"]), translate=False) if warning: split = colsub.row().split(factor=0.15) split.label(text="Warning:") split.label(text=" " + warning, icon='ERROR') separators = 2 split = colsub.row().split(factor=0.15) split.label(text="Internet:") if info["wiki_url"]: split.operator("wm.url_open", text="Documentation", icon='HELP').url = info["wiki_url"] separators -= 1 split.operator( "wm.url_open", text="Report a Bug", icon='URL' ).url = info.get( "tracker_url", "http://developer.blender.org/maniphest/task/create/?project=3&type=Bug" ) split.operator("wm.url_open", text="Manual download", icon='URL').url = addon["url"] if "registry-report-url" in addon: split.operator( "wm.url_open", text="Report to registry", icon='ERROR').url = addon["registry-report-url"] separators -= 1 for i in range(separators): split.separator()
def draw(self, context): layout = self.layout if lastError != ERROR_NONE: box = layout.box() box.label(icon='ERROR', text=error_titles[lastError]) if lastError == ERROR_EXTRACT_MANUALLY: box.label("The downloaded file is not recognized. It should be an archive that you need to extract manually.") split = box.split(0.6) split.label("By installing 7-Zip and adding it to your PATH, the registry recognizes more formats.") row = split.row() row.operator("wm.url_open", icon='URL', text="Download 7-Zip").url = "http://www.7-zip.org/download.html" row.operator("wm.url_open", icon='URL', text="Installation instructions").url = "http://www.7-zip.org/download.html" elif lastError == ERROR_FAILED_COPY: box.label("The addon file is unreachable.") elif lastError == ERROR_FAILED_DOWNLOAD: box.label("Something may be wrong with your Internet connection. Please try again later.") elif lastError == ERROR_FAILED_REQUEST: box.label("The server hosting the addon may be down. Please try again later.") box.label("The addon may have moved to another URL. If you think this is the case, please report it using the following button, so that the maintainer will update the registry.") elif lastError == ERROR_FAILED_RETRIEVE_ADDON_LIST: box.label("The registry server may be down. Please try again later.") box.label("The registry may have moved to another URL. If you think this is the case, please report it using the following button, so that the maintainer will update the registry.") elif lastError == ERROR_HASH_MISMATCH: box.label("The downloaded addon does not match the registry record. For security reasons, it won't be installed.") box.label("It could mean that the addon's author has uploaded a new version with the same URL.") box.label("If you think this is the case, please report it using the following button, so that the maintainer will update the registry.") elif lastError == ERROR_NO_HASH: box.label("The registry record does not contain an expected hash, therefore the addon authenticity can't be verified.") box.label("You may be using an unofficial registry. If this is the case, please report it to its maintainers.") split = box.split(0.9) split.operator("wm.url_open", icon='URL', text="If the error persists, please report an issue to the registry maintainers").url = "https://github.com/Bloutiouf/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/issues/new" split.operator("addon_registry.hide_error", icon='X') addon_dir = get_addon_dir() userpref = context.user_preferences wm = context.window_manager installed_addons = {} for mod in addon_utils.modules(refresh=False): installed_addons[mod.__name__] = mod enabled_addon_names = {addon.module for addon in userpref.addons} split = layout.split(percentage=0.2) col = split.column() col.operator(UpdateDatabase.bl_idname, icon='FILE_REFRESH') col.separator() col.prop(wm, "addon_registry_search", text="", icon='VIEWZOOM') col.label(text="Categories") col.prop(wm, "addon_registry_filter", expand=True) col.separator() col.operator(ResetConfiguration.bl_idname, icon='CANCEL') col = split.column() filter = wm.addon_registry_filter search = wm.addon_registry_search.lower() for name, addon in sorted_addons: info = addon["info"] available_version = info["version"] show_expanded = addon.get("show_expanded", False) installed_addon = installed_addons.get(name, None) installed_version = None is_installed = bool(installed_addon) is_newer_available = False is_enabled = False if is_installed: installed_info = addon_utils.module_bl_info(installed_addon) installed_version = list(installed_info["version"]) is_newer_available = is_newer_version(available_version, installed_version) is_enabled = name in enabled_addon_names if ((filter == "All") or (filter == "New Version Available" and is_newer_available) or (filter == info["category"]) or (filter == "Installed" and is_installed) or (filter == "Not Installed" and not is_installed) ): if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): continue else: continue peers = addon.get("peers", None) if peers and (type(peers) is not list or len(peers) == 0): peers = None warning = info.get("warning", None) col_box = col.column() box = col_box.box() colsub = box.column() row = colsub.row() row.operator(Expand.bl_idname, icon='TRIA_DOWN' if show_expanded else "TRIA_RIGHT", emboss=False).addon_name = name sub = row.split(0.6) text = sub.row() text.label(text="%s: %s" % (info["category"], info["name"])) if peers: text.label(icon='LINK_AREA') if warning: text.label(icon='ERROR') buttons = sub.split(0.5) if is_installed: buttons.operator("wm.addon_remove", text=".".join(map(str, installed_version)), icon='CANCEL').module = name else: buttons.label("Not installed") if is_installed and not is_newer_available: buttons.label("Latest version") else: buttons.operator(Install.bl_idname, text=".".join(map(str, available_version)), icon='WORLD').addon_name = name if is_installed: if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = name else: sub = row.row() sub.active = False sub.label(icon='CHECKBOX_DEHLT', text="") if show_expanded: if peers: colsub.row().label(icon='LINK_AREA', text="Bundled with: " + ", ".join(configuration["addons"][peer]["info"]["name"] for peer in peers)) if info["description"]: split = colsub.row().split(percentage=0.15) split.label(text="Description:") split.label(text=info["description"]) if info["location"]: split = colsub.row().split(percentage=0.15) split.label(text="Location:") split.label(text=info["location"]) if info["author"]: split = colsub.row().split(percentage=0.15) split.label(text="Author:") split.label(text=info["author"], translate=False) if info["version"]: split = colsub.row().split(percentage=0.15) split.label(text="Version:") split.label(text=".".join(str(x) for x in info["version"]), translate=False) if warning: split = colsub.row().split(percentage=0.15) split.label(text="Warning:") split.label(text=" " + warning, icon='ERROR') separators = 2 split = colsub.row().split(percentage=0.15) split.label(text="Internet:") if info["wiki_url"]: split.operator("wm.url_open", text="Documentation", icon='HELP').url = info["wiki_url"] separators -= 1 split.operator("wm.url_open", text="Report a Bug", icon='URL').url = info.get( "tracker_url", "http://developer.blender.org/maniphest/task/create/?project=3&type=Bug") split.operator("wm.url_open", text="Manual download", icon='URL').url = addon["url"] if "registry-report-url" in addon: split.operator("wm.url_open", text="Report to registry", icon='ERROR').url = addon["registry-report-url"] separators -= 1 for i in range(separators): split.separator()
def fbx_header_elements(root, scene_data, time=None): """ Write boiling code of FBX root. time is expected to be a datetime.datetime object, or None (using now() in this case). """ app_vendor = "Blender Foundation" app_name = "Blender (stable FBX IO)" app_ver = bpy.app.version_string import addon_utils import sys addon_ver = addon_utils.module_bl_info(sys.modules[__package__])['version'] # ##### Start of FBXHeaderExtension element. header_ext = elem_empty(root, b"FBXHeaderExtension") elem_data_single_int32(header_ext, b"FBXHeaderVersion", FBX_HEADER_VERSION) elem_data_single_int32(header_ext, b"FBXVersion", FBX_VERSION) # No encryption! elem_data_single_int32(header_ext, b"EncryptionType", 0) if time is None: time = datetime.datetime.now() elem = elem_empty(header_ext, b"CreationTimeStamp") elem_data_single_int32(elem, b"Version", 1000) elem_data_single_int32(elem, b"Year", time.year) elem_data_single_int32(elem, b"Month", time.month) elem_data_single_int32(elem, b"Day", time.day) elem_data_single_int32(elem, b"Hour", time.hour) elem_data_single_int32(elem, b"Minute", time.minute) elem_data_single_int32(elem, b"Second", time.second) elem_data_single_int32(elem, b"Millisecond", time.microsecond // 1000) elem_data_single_string_unicode(header_ext, b"Creator", "%s - %s - %d.%d.%d" % (app_name, app_ver, addon_ver[0], addon_ver[1], addon_ver[2])) # 'SceneInfo' seems mandatory to get a valid FBX file... # TODO use real values! # XXX Should we use scene.name.encode() here? scene_info = elem_data_single_string(header_ext, b"SceneInfo", fbx_name_class(b"GlobalInfo", b"SceneInfo")) scene_info.add_string(b"UserData") elem_data_single_string(scene_info, b"Type", b"UserData") elem_data_single_int32(scene_info, b"Version", FBX_SCENEINFO_VERSION) meta_data = elem_empty(scene_info, b"MetaData") elem_data_single_int32(meta_data, b"Version", FBX_SCENEINFO_VERSION) elem_data_single_string(meta_data, b"Title", b"") elem_data_single_string(meta_data, b"Subject", b"") elem_data_single_string(meta_data, b"Author", b"") elem_data_single_string(meta_data, b"Keywords", b"") elem_data_single_string(meta_data, b"Revision", b"") elem_data_single_string(meta_data, b"Comment", b"") props = elem_properties(scene_info) elem_props_set(props, "p_string_url", b"DocumentUrl", "/foobar.fbx") elem_props_set(props, "p_string_url", b"SrcDocumentUrl", "/foobar.fbx") original = elem_props_compound(props, b"Original") original("p_string", b"ApplicationVendor", app_vendor) original("p_string", b"ApplicationName", app_name) original("p_string", b"ApplicationVersion", app_ver) original("p_datetime", b"DateTime_GMT", "01/01/1970 00:00:00.000") original("p_string", b"FileName", "/foobar.fbx") lastsaved = elem_props_compound(props, b"LastSaved") lastsaved("p_string", b"ApplicationVendor", app_vendor) lastsaved("p_string", b"ApplicationName", app_name) lastsaved("p_string", b"ApplicationVersion", app_ver) lastsaved("p_datetime", b"DateTime_GMT", "01/01/1970 00:00:00.000") # ##### End of FBXHeaderExtension element. # FileID is replaced by dummy value currently... elem_data_single_bytes(root, b"FileId", b"FooBar") # CreationTime is replaced by dummy value currently, but anyway... elem_data_single_string_unicode(root, b"CreationTime", "{:04}-{:02}-{:02} {:02}:{:02}:{:02}:{:03}" "".format(time.year, time.month, time.day, time.hour, time.minute, time.second, time.microsecond * 1000)) elem_data_single_string_unicode(root, b"Creator", "%s - %s - %d.%d.%d" % (app_name, app_ver, addon_ver[0], addon_ver[1], addon_ver[2])) # ##### Start of GlobalSettings element. global_settings = elem_empty(root, b"GlobalSettings") scene = scene_data.scene elem_data_single_int32(global_settings, b"Version", 1000) props = elem_properties(global_settings) up_axis, front_axis, coord_axis = RIGHT_HAND_AXES[scene_data.settings.to_axes] #~ # DO NOT take into account global scale here! That setting is applied to object transformations during export #~ # (in other words, this is pure blender-exporter feature, and has nothing to do with FBX data). #~ if scene_data.settings.apply_unit_scale: #~ # Unit scaling is applied to objects' scale, so our unit is effectively FBX one (centimeter). #~ scale_factor_org = 1.0 #~ scale_factor = 1.0 / units_blender_to_fbx_factor(scene) #~ else: #~ scale_factor_org = units_blender_to_fbx_factor(scene) #~ scale_factor = scale_factor_org scale_factor = scale_factor_org = scene_data.settings.unit_scale elem_props_set(props, "p_integer", b"UpAxis", up_axis[0]) elem_props_set(props, "p_integer", b"UpAxisSign", up_axis[1]) elem_props_set(props, "p_integer", b"FrontAxis", front_axis[0]) elem_props_set(props, "p_integer", b"FrontAxisSign", front_axis[1]) elem_props_set(props, "p_integer", b"CoordAxis", coord_axis[0]) elem_props_set(props, "p_integer", b"CoordAxisSign", coord_axis[1]) elem_props_set(props, "p_integer", b"OriginalUpAxis", -1) elem_props_set(props, "p_integer", b"OriginalUpAxisSign", 1) elem_props_set(props, "p_double", b"UnitScaleFactor", scale_factor) elem_props_set(props, "p_double", b"OriginalUnitScaleFactor", scale_factor_org) elem_props_set(props, "p_color_rgb", b"AmbientColor", (0.0, 0.0, 0.0)) elem_props_set(props, "p_string", b"DefaultCamera", "Producer Perspective") # Global timing data. r = scene.render _, fbx_fps_mode = FBX_FRAMERATES[0] # Custom framerate. fbx_fps = fps = r.fps / r.fps_base for ref_fps, fps_mode in FBX_FRAMERATES: if similar_values(fps, ref_fps): fbx_fps = ref_fps fbx_fps_mode = fps_mode elem_props_set(props, "p_enum", b"TimeMode", fbx_fps_mode) elem_props_set(props, "p_timestamp", b"TimeSpanStart", 0) elem_props_set(props, "p_timestamp", b"TimeSpanStop", FBX_KTIME) elem_props_set(props, "p_double", b"CustomFrameRate", fbx_fps)
def draw(self, context): import os import addon_utils layout = self.layout userpref = context.user_preferences used_ext = {ext.module for ext in userpref.addons} userpref_addons_folder = os.path.join(userpref.filepaths.script_directory, "addons") scripts_addons_folder = bpy.utils.user_resource('SCRIPTS', "addons") # collect the categories that can be filtered on addons = [(mod, addon_utils.module_bl_info(mod)) for mod in addon_utils.modules(refresh=False)] split = layout.split(percentage=0.2) col = split.column() col.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM') col.label(text="Supported Level") col.prop(context.window_manager, "addon_support", expand=True) col.label(text="Categories") col.prop(context.window_manager, "addon_filter", expand=True) col = split.column() # set in addon_utils.modules_refresh() if addon_utils.error_duplicates: self.draw_error(col, "Multiple addons using the same name found!\n" "likely a problem with the script search path.\n" "(see console for details)", ) if addon_utils.error_encoding: self.draw_error(col, "One or more addons do not have UTF-8 encoding\n" "(see console for details)", ) filter = context.window_manager.addon_filter search = context.window_manager.addon_search.lower() support = context.window_manager.addon_support # initialized on demand user_addon_paths = [] for mod, info in addons: module_name = mod.__name__ is_enabled = module_name in used_ext if info["support"] not in support: continue # check if addon should be visible with current filters if ((filter == "All") or (filter == info["category"]) or (filter == "Enabled" and is_enabled) or (filter == "Disabled" and not is_enabled) or (filter == "User" and (mod.__file__.startswith((scripts_addons_folder, userpref_addons_folder)))) ): if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): continue else: continue # Addon UI Code col_box = col.column() box = col_box.box() colsub = box.column() row = colsub.row() row.operator("wm.addon_expand", icon='TRIA_DOWN' if info["show_expanded"] else 'TRIA_RIGHT', emboss=False).module = module_name sub = row.row() sub.active = is_enabled sub.label(text='%s: %s' % (info["category"], info["name"])) if info["warning"]: sub.label(icon='ERROR') # icon showing support level. sub.label(icon=self._support_icon_mapping.get(info["support"], 'QUESTION')) if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name # Expanded UI (only if additional info is available) if info["show_expanded"]: if info["description"]: split = colsub.row().split(percentage=0.15) split.label(text="Description:") split.label(text=info["description"]) if info["location"]: split = colsub.row().split(percentage=0.15) split.label(text="Location:") split.label(text=info["location"]) if mod: split = colsub.row().split(percentage=0.15) split.label(text="File:") split.label(text=mod.__file__, translate=False) if info["author"]: split = colsub.row().split(percentage=0.15) split.label(text="Author:") split.label(text=info["author"], translate=False) if info["version"]: split = colsub.row().split(percentage=0.15) split.label(text="Version:") split.label(text='.'.join(str(x) for x in info["version"]), translate=False) if info["warning"]: split = colsub.row().split(percentage=0.15) split.label(text="Warning:") split.label(text=' ' + info["warning"], icon='ERROR') user_addon = USERPREF_PT_addons.is_user_addon(mod, user_addon_paths) tot_row = bool(info["wiki_url"]) + bool(user_addon) if tot_row: split = colsub.row().split(percentage=0.15) split.label(text="Internet:") if info["wiki_url"]: split.operator("wm.url_open", text="Documentation", icon='HELP').url = info["wiki_url"] tracker_url = "http://developer.blender.org/maniphest/task/create/?project=3&type=Bug" split.operator("wm.url_open", text="Report a Bug", icon='URL').url = tracker_url if user_addon: split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__ for i in range(4 - tot_row): split.separator() # Show addon user preferences if is_enabled: addon_preferences = userpref.addons[module_name].preferences if addon_preferences is not None: draw = getattr(addon_preferences, "draw", None) if draw is not None: addon_preferences_class = type(addon_preferences) box_prefs = col_box.box() box_prefs.label("Preferences:") addon_preferences_class.layout = box_prefs try: draw(context) except: import traceback traceback.print_exc() box_prefs.label(text="Error (see console)", icon='ERROR') del addon_preferences_class.layout # Append missing scripts # First collect scripts that are used but have no script file. module_names = {mod.__name__ for mod, info in addons} missing_modules = {ext for ext in used_ext if ext not in module_names} if missing_modules and filter in {"All", "Enabled"}: col.column().separator() col.column().label(text="Missing script files") module_names = {mod.__name__ for mod, info in addons} for module_name in sorted(missing_modules): is_enabled = module_name in used_ext # Addon UI Code box = col.column().box() colsub = box.column() row = colsub.row() row.label(text=module_name, translate=False, icon='ERROR') if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name
def draw(self, context): import os import addon_utils userpref = context.user_preferences used_ext = {ext.module for ext in userpref.addons} userpref_addons_folder = os.path.join( userpref.filepaths.script_directory, "addons") scripts_addons_folder = bpy.utils.user_resource('SCRIPTS', "addons") #collect the categories that can be filtered on addons = [(mod, addon_utils.module_bl_info(mod)) for mod in addon_utils.modules(refresh=True)] #Management header layout layout = self.layout layout.label("Run Blender as admin for full permission", icon='LAYER_USED') split = layout.split( percentage=0.60, align=True, ) if bpy.data.window_managers["WinMan"].addon_filter == 'Favourites': split.operator("wm.check_fav", icon='SPACE2', text="Favourites") else: split.operator("wm.check_fav", icon='SPACE3', text="Favourites") split.operator("wm.user_adon", text="User") split.operator("wm.ena_adon", icon='SAVE_AS', text="") split.operator("wm.all_adon", icon='BOOKMARKS', text="") #searche layout layout = self.layout layout.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM') row = layout.row() split = layout.split() col = split.column() filter = context.window_manager.addon_filter search = context.window_manager.addon_search.lower() support = context.window_manager.addon_support #initialized on demand user_addon_paths = [] addon_numb = 0 for mod, info in addons: module_name = mod.__name__ module_realpath = mod.__file__ is_enabled = module_name in used_ext if info["support"] not in support: continue #serche parmetres if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): continue else: continue # check if addon should be visible with current filters if ((filter == "All") or (filter == info["category"]) or (filter == "Enabled" and is_enabled) or (filter == "Disabled" and not is_enabled) or (filter == "User" and (mod.__file__.startswith( (scripts_addons_folder, userpref_addons_folder))))): #limit visible addon on 'All' folder if bpy.data.window_managers[ "WinMan"].addon_filter == 'All' and addon_numb < 10: # Addon UI Code col_box = col.column() box = col_box.box() colsub = box.column() row = colsub.row() if info["category"] == "Favourites": row.operator("wm.un_chemin", icon='PINNED', emboss=False, text="").chemin = module_realpath sub = row.row() sub.label(info["name"], icon='SMALL_TRI_RIGHT_VEC') else: row.operator("wm.get_chemin", icon='UNPINNED', emboss=False, text="").chemin = module_realpath sub = row.row() sub.label(info["name"], ) sub.operator("wm.addon_remove", text="", icon='PANEL_CLOSE', emboss=False).module = mod.__name__ if is_enabled: row.operator("wm.addon_disable", icon='FILE_TICK', text="", emboss=False).module = module_name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name #incrementation for limitation addon_numb += 1 if bpy.data.window_managers["WinMan"].addon_filter != 'All': # Addon UI Code col_box = col.column() box = col_box.box() colsub = box.column() row = colsub.row() if info["category"] == "Favourites": row.operator("wm.un_chemin", icon='PINNED', emboss=False, text="").chemin = module_realpath sub = row.row() sub.label(info["name"], icon='SMALL_TRI_RIGHT_VEC') else: row.operator("wm.get_chemin", icon='UNPINNED', emboss=False, text="").chemin = module_realpath sub = row.row() sub.label(info["name"], ) sub.operator("wm.addon_remove", text="", icon='PANEL_CLOSE', emboss=False).module = mod.__name__ if is_enabled: row.operator("wm.addon_disable", icon='FILE_TICK', text="", emboss=False).module = module_name else: row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name
def dump_addon_messages(module_name, do_checks, settings): import addon_utils # Get current addon state (loaded or not): was_loaded = addon_utils.check(module_name)[1] # Enable our addon. addon = utils.enable_addons(addons={module_name})[0] addon_info = addon_utils.module_bl_info(addon) ver = addon_info["name"] + " " + ".".join( str(v) for v in addon_info["version"]) rev = 0 date = datetime.datetime.now() pot = utils.I18nMessages.gen_empty_messages(settings.PARSER_TEMPLATE_ID, ver, rev, date, date.year, settings=settings) msgs = pot.msgs minus_pot = utils.I18nMessages.gen_empty_messages( settings.PARSER_TEMPLATE_ID, ver, rev, date, date.year, settings=settings) minus_msgs = minus_pot.msgs check_ctxt = _gen_check_ctxt(settings) if do_checks else None minus_check_ctxt = _gen_check_ctxt(settings) if do_checks else None # Get strings from RNA, our addon being enabled. print("A") reports = _gen_reports(check_ctxt) print("B") dump_rna_messages(msgs, reports, settings) print("C") # Now disable our addon, and rescan RNA. utils.enable_addons(addons={module_name}, disable=True) print("D") reports["check_ctxt"] = minus_check_ctxt print("E") dump_rna_messages(minus_msgs, reports, settings) print("F") # Restore previous state if needed! if was_loaded: utils.enable_addons(addons={module_name}) # and make the diff! for key in minus_msgs: if key != settings.PO_HEADER_KEY: del msgs[key] if check_ctxt: _diff_check_ctxt(check_ctxt, minus_check_ctxt) # and we are done with those! del minus_pot del minus_msgs del minus_check_ctxt # get strings from UI layout definitions text="..." args reports["check_ctxt"] = check_ctxt dump_py_messages(msgs, reports, {addon}, settings, addons_only=True) pot.unescape( ) # Strings gathered in py/C source code may contain escaped chars... print_info(reports, pot) print("Finished extracting UI messages!") return pot
with code_coverage_maybe: # start coverage before importing and registering add-on module import bpy addon_module = find_addon() print("Add-on:", addon_module or "not found") if not addon_module: remove_addon_on_exit = addon_zip_and_install() bpy.ops.preferences.addon_refresh() addon_module = find_addon() print("Installed Add-on:", addon_module or "not installed") bl_info = addon_utils.module_bl_info(addon_module) print("Version:", bl_info.get("version", (-1, -1, -1))) addon_enable_if_not_loaded() print("===== Tests =====") exit_code = run_tests() print("=== End Tests ===") if remove_addon_on_exit: print("Removing Add-on...", end="", flush=True) path_user_scripts_addons = bpy.utils.user_resource('SCRIPTS', "addons") path_addon = os.path.abspath( os.path.join(path_user_scripts_addons, f"{ADDON}")) shutil.rmtree(path_addon) print("done")