def wrapper(*args, **kwargs): start_time = time.time() res = f(*args, **kwargs) function_name = f.func_name if python.is_python2() else f.__name__ logger.info('<{}> Elapsed time : {}'.format(function_name, time.time() - start_time)) return res
def register_libs(project_inst): """ Function that registera all available libs for given project :param project_inst: ArtellaProject """ from tpDcc.libs.python import python if python.is_python2(): import pkgutil as loader else: import importlib as loader libs_found = project_inst.config_data.get('libs', list()) libs_to_register = dict() libs_path = '{}.libs.{}' for lib_name in libs_found: for pkg in ['artellapipe', project_inst.get_clean_name()]: pkg_path = libs_path.format(pkg, lib_name) try: pkg_loader = loader.find_loader(pkg_path) except Exception: pkg_loader = None if pkg_loader is not None: if lib_name not in libs_to_register: libs_to_register[lib_name] = list() libs_to_register[lib_name].append(pkg_loader) for pkg_loaders in libs_to_register.values(): for pkg_loader in pkg_loaders: libs.LibsManager().register_lib(project=project_inst, pkg_loader=pkg_loader)
def _load_package_toolsets(self, package_name, tools_to_load): """ Loads all toolsets available in given package :param package_name: str :param tools_to_load: list """ if not tools_to_load: return tools_to_load = python.force_list(tools_to_load) paths_to_register = OrderedDict() tools_path = '{}.tools.{}' tools_paths_to_load = list() for tool_name in tools_to_load: pkg_path = tools_path.format(package_name, tool_name) pkg_loader = loader.find_loader(pkg_path) if not pkg_loader: LOGGER.debug('No loader found for "{}"'.format(tool_name)) continue if tool_name not in paths_to_register: paths_to_register[tool_name] = list() package_filename = pkg_loader.filename if python.is_python2( ) else os.path.dirname(pkg_loader.path) if package_filename not in tools_paths_to_load: tools_paths_to_load.append(package_filename) # Find where toolset widgets are located if tools_paths_to_load: self._manager.register_paths(tools_paths_to_load, package_name=package_name)
def load_module_from_source(file_path, unique_namespace=False): """ Loads a Python from given source file :param file_path: :param unique_namespace: bool :return: """ file_name = os.path.splitext(os.path.basename(file_path))[0] module_name = '{}{}'.format(file_name, str( uuid.uuid4())) if unique_namespace else file_name try: if python.is_python2(): if file_path.endswith('.py'): return imp.load_source(module_name, file_path) elif file_path.endswith('.pyc'): return imp.load_compiled(module_name, file_path) else: return SourceFileLoader(module_name, file_path).load_module() except BaseException: logger.debug('Failed trying to direct load : {} | {}'.format( file_path, traceback.format_exc())) return None
def wrapinstance(ptr, base=None): if ptr is None: return None ptr_type = long if python.is_python2() else int ptr = ptr_type(ptr) if 'shiboken' in globals(): if base is None: qObj = shiboken.wrapInstance(ptr_type(ptr), QObject) meta_obj = qObj.metaObject() cls = meta_obj.className() super_cls = meta_obj.superClass().className() if hasattr(QtGui, cls): base = getattr(QtGui, cls) elif hasattr(QtGui, super_cls): base = getattr(QtGui, super_cls) else: base = QWidget try: return shiboken.wrapInstance(ptr_type(ptr), base) except Exception: from PySide.shiboken import wrapInstance return wrapInstance(ptr_type(ptr), base) elif 'sip' in globals(): base = QObject return shiboken.wrapinstance(ptr_type(ptr), base) else: print('Failed to wrap object ...') return None
def write(self, msg): """ Add message to the console's output, on a new line :param msg: str """ self.insertPlainText(msg + '\n') self.moveCursor(QTextCursor.End) self._buffer.write(unicode(msg) if python.is_python2() else str(msg))
def unwrapinstance(object): """ Unwraps objects with PySide """ if python.is_python2(): return long(shiboken.getCppPointer(object)[0]) else: return int(shiboken.getCppPointer(object)[0])
def node_handle_exists(node_id): """ Checks if exists a node with the given ID :param node_id: int :return: bool """ native_node = get_node_by_handle(long(node_id) if python.is_python2() else int(node_id)) return native_node is not None
def register_package_tools(self, package_name, tools_to_register=None): """ Registers all tools available in given package """ found_tools = list() if not tools_to_register: return tools_to_register = python.force_list(tools_to_register) tools_path = '{}.tools.{}' for tool_name in tools_to_register: pkg_path = tools_path.format(package_name, tool_name) if python.is_python2(): pkg_loader = loader.find_loader(pkg_path) else: pkg_loader = importlib.util.find_spec(pkg_path) if not pkg_loader: continue tool_path = path_utils.clean_path( pkg_loader.filename if python.is_python2( ) else os.path.dirname(pkg_loader.origin)) if not tool_path or not os.path.isdir(tool_path): continue found_tools.append(tool_path) if not found_tools: logger.warning( 'No tools found in package "{}"'.format(package_name)) found_tools = list(set(found_tools)) self.register_paths(found_tools, package_name=package_name) for tool_class in self.plugins(package_name=package_name): if not tool_class: continue if not tool_class.PACKAGE: tool_class.PACKAGE = package_name if tool_class.TOOLSET_CLASS: tool_class.TOOLSET_CLASS.ID = tool_class.ID
def write_warning(self, msg): """ Adds a warning yellow message to the console :param msg: str """ msg_html = "<font color=\"Yellow\"> " + msg + "\n</font><br>" self.insertHtml(msg_html) self.moveCursor(QTextCursor.End) self._buffer.write(unicode(msg) if python.is_python2() else str(msg))
def write_error(self, msg): """ Adds an error message to the console :param msg: str """ msg_html = "<font color=\"Red\">ERROR: " + msg + "\n</font><br>" msg = 'ERROR: ' + msg self.insertHtml(msg_html) self.moveCursor(QTextCursor.End) self._buffer.write(unicode(msg) if python.is_python2() else str(msg))
def format(cls, data=None, options=None, dpi=1, **kwargs): """ Returns style with proper format :param data: str :param options: dict :param dpi: float :return: str """ if options: keys = options.keys() if python.is_python2(): keys.sort(key=len, reverse=True) else: keys = sorted(keys, key=len, reverse=True) for key in keys: key_value = options[key] str_key_value = str(key_value) option_value = str(key_value) if str_key_value.startswith('@^'): option_value = str(utils.dpi_scale(int(str_key_value[2:]))) elif str_key_value.startswith('^'): option_value = str(utils.dpi_scale(int(str_key_value[1:]))) elif 'icon' in key: theme_name = kwargs.get('theme_name', 'default') or 'default' resource_path = resources.get('icons', theme_name, str(key_value)) if resource_path and os.path.isfile(resource_path): option_value = resource_path elif color.string_is_hex(str_key_value): try: color_list = color.hex_to_rgba(str_key_value) option_value = 'rgba({}, {}, {}, {})'.format( color_list[0], color_list[1], color_list[2], color_list[3]) except ValueError: # This exception will be raised if we try to convert an attribute that is not a color. option_value = key_value data = data.replace('@{}'.format(key), option_value) re_dpi = re.compile('[0-9]+[*]DPI') new_data = list() for line in data.split('\n'): dpi_ = re_dpi.search(line) if dpi_: new = dpi_.group().replace('DPI', str(dpi)) val = int(eval(new)) line = line.replace(dpi_.group(), str(val)) new_data.append(line) data = '\n'.join(new_data) return data
def register_package_libs(self, package_name, libs_to_register=None): """ Registers all libraries available in given package """ found_libs = list() if not libs_to_register: return libs_to_register = python.force_list(libs_to_register) libs_path = '{}.libs.{}' for lib_name in libs_to_register: pkg_path = libs_path.format(package_name, lib_name) if python.is_python2(): pkg_loader = loader.find_loader(pkg_path) else: pkg_loader = importlib.util.find_spec(pkg_path) if not pkg_loader: continue lib_path = path_utils.clean_path( pkg_loader.filename if python.is_python2( ) else os.path.dirname(pkg_loader.origin)) if not lib_path or not os.path.isdir(lib_path): continue found_libs.append(lib_path) if not found_libs: logger.warning( 'No libraries found in package "{}"'.format(package_name)) found_libs = list(set(found_libs)) self.register_paths(found_libs, package_name=package_name) # Once plugins are registered we load them plugins = self.plugins(package_name=package_name) for plugin in plugins: plugin.load()
def image_to_base64(image_path): """ Converts image file to base64 :param image_path: str :return: str """ if os.path.isfile(image_path): with open(image_path, 'rb') as image_file: base64_data = base64.b64encode(image_file.read()) if python.is_python2(): return base64_data else: return base64_data.decode("utf-8")
def fields(cls, identifier): ctime = str(time.time()).split('.')[0] user = getpass.getuser() if user and python.is_python2(): user.decode(locale.getpreferredencoding()) name, extension = os.path.splitext(os.path.basename(identifier)) return OrderedDict([('name', name), ('extension', extension), ('directory', os.path.dirname(identifier)), ('folder', os.path.isdir(identifier)), ('user', user), ('modified', fileio.get_last_modified_date(identifier)), ('ctime', ctime)])
def normalize_path(path): """ Normalizes a path to make sure that path only contains forward slashes :param path: str, path to normalize :return: str, normalized path """ path = path.replace(BAD_SEPARATOR, SEPARATOR).replace(PATH_SEPARATOR, SEPARATOR) if python.is_python2(): try: path = unicode(path.replace(r'\\', r'\\\\'), "unicode_escape").encode('utf-8') except TypeError: path = path.replace(r'\\', r'\\\\').encode('utf-8') return path.rstrip('/')
def write_json(self, dict_data): """ Writes given JSON data (dict) into file :param dict_data: dict """ self.write_file() try: if python.is_python2(): json.dump(dict_data, self.open_file, indent=4, sort_keys=False) else: json.dump(dict(dict_data), self.open_file, indent=4, sort_keys=False) except Exception as exc: logger.exception('Impossible to save JSON file: "{}"'.format(exc)) self.close_file()
def read(self): contents = dict() if not os.path.isfile(self._path): return contents try: with open(self._path, 'r+b') as fh: contents = pickle.load(fh) if python.is_python2( ) else pickle.load(fh, encoding='bytes') except pickle.UnpicklingError: _broken_files.setdefault(self._path, 0) times_hit = _broken_files[self._path] if times_hit < 3: logger.error('Failed to load pickle preference "{}"'.format( self._path)) times_hit += 1 _broken_files[self._path] = times_hit self.clear() self.update(contents)
def register_package_libs(self, pkg_name, root_pkg_name=None, libs_to_register=None, dev=True, config_dict=None): """ Registers all libraries available in given package """ environment = 'development' if dev else 'production' if not libs_to_register: return libs_to_register = python.force_list(libs_to_register) if config_dict is None: config_dict = dict() libs_path = '{}.libs.{}' for lib_name in libs_to_register: pkg_path = libs_path.format(pkg_name, lib_name) if python.is_python2(): pkg_loader = loader.find_loader(pkg_path) else: pkg_loader = importlib.util.find_spec(pkg_path) if not pkg_loader: # if tool_name in self._tools_to_load: # self._tools_to_load.pop(tool_name) continue else: lib_data = { 'loaders': pkg_loader, 'pkg_name': pkg_name, 'root_pkg_name': root_pkg_name, 'environment': environment, 'config_dict': config_dict } self._libs_to_load[lib_name] = lib_data return self._libs_to_load
def qhash(inputstr): instr = "" if python.is_python2(): if isinstance(inputstr, str): instr = inputstr elif isinstance(inputstr, unicode): instr = inputstr.encode("utf8") else: return -1 else: if python.is_string(inputstr): instr = inputstr else: return -1 h = 0x00000000 for i in range(0, len(instr)): h = (h << 4) + ord(instr[i]) h ^= (h & 0xf0000000) >> 23 h &= 0x0fffffff return h
def __init__(self, title, commands_data, controller, parent=None): self._commands_data = commands_data or dict() self._widgets = dict() self._buttons = list() self._current_action = None self._controller = controller self._controller_functions_mapping = dict() super(CommandRigToolBoxWidget, self).__init__(title=title, parent=parent) if self._controller: predicate = inspect.ismethod if python.is_python2( ) else inspect.isfunction controller_functions = inspect.getmembers( self._controller.__class__, predicate=predicate) for controller_fn_data in controller_functions: if controller_fn_data[0] in ['__init__']: continue controller_fn = getattr(self._controller, controller_fn_data[0]) if not controller_fn: continue self._controller_functions_mapping[ controller_fn_data[0]] = controller_fn added_categories = list() for name, data in self._commands_data.items(): categories = data.get('categories', list()) for category in categories: if not category or category in added_categories: continue category_widget = self._add_category(category) if not category_widget: continue self._accordion.add_item(category, category_widget) added_categories.append(category)
def load_plugin(self, pkg_name, pkg_loaders, environment, root_pkg_name=None, config_dict=None, load=True): """ Implements load_plugin function Registers a plugin instance to the manager :param pkg_name: str :param pkg_loaders: plugin instance to register :param environment: :param root_pkg_name: :param config_dict: :param load: :return: Plugin """ if not pkg_loaders: return False package_loader = pkg_loaders[0] if isinstance(pkg_loaders, (list, tuple)) else pkg_loaders if not package_loader: return False if hasattr(package_loader, 'loader'): if not package_loader.loader: return False plugin_path = package_loader.filename if python.is_python2( ) else os.path.dirname(package_loader.loader.path) plugin_name = package_loader.fullname if python.is_python2( ) else package_loader.loader.name if not config_dict: config_dict = dict() local = os.getenv('APPDATA') or os.getenv('HOME') config_dict.update({ 'join': os.path.join, 'user': os.path.expanduser('~'), 'filename': plugin_path, 'fullname': plugin_name, 'root': path_utils.clean_path(plugin_path), 'local': local, 'home': local }) if pkg_name not in self._plugins: self._plugins[pkg_name] = dict() tools_found = list() version_found = None packages_to_walk = [plugin_path] if python.is_python2() else [ os.path.dirname(plugin_path) ] for sub_module in pkgutil.walk_packages(packages_to_walk): importer, sub_module_name, _ = sub_module qname = '{}.{}'.format(plugin_name, sub_module_name) try: mod = importer.find_module(sub_module_name).load_module( sub_module_name) except Exception: # LOGGER.exception('Impossible to register plugin: "{}"'.format(plugin_path)) continue if qname.endswith('__version__') and hasattr(mod, '__version__'): if version_found: LOGGER.warning( 'Already found version: "{}" for "{}"'.format( version_found, plugin_name)) else: version_found = getattr(mod, '__version__') mod.LOADED = load for cname, obj in inspect.getmembers(mod, inspect.isclass): for interface in self._interfaces: if issubclass(obj, interface): tool_config_dict = obj.config_dict( file_name=plugin_path) or dict() if not tool_config_dict: continue tool_id = tool_config_dict.get('id', None) tool_config_name = tool_config_dict.get('name', None) # tool_icon = tool_config_dict.get('icon', None) if not tool_id: LOGGER.warning( 'Impossible to register tool "{}" because its ID is not defined!' .format(tool_id)) continue if not tool_config_name: LOGGER.warning( 'Impossible to register tool "{}" because its name is not defined!' .format(tool_config_name)) continue if root_pkg_name and root_pkg_name in self._plugins and tool_id in self._plugins[ root_pkg_name]: LOGGER.warning( 'Impossible to register tool "{}" because its ID "{}" its already defined!' .format(tool_config_name, tool_id)) continue if not version_found: version_found = '0.0.0' obj.VERSION = version_found obj.FILE_NAME = plugin_path obj.FULL_NAME = plugin_name tools_found.append((qname, version_found, obj)) version_found = True break if not tools_found: LOGGER.warning( 'No tools found in module "{}". Skipping ...'.format( plugin_path)) return False if len(tools_found) > 1: LOGGER.warning( 'Multiple tools found ({}) in module "{}". Loading first one. {} ...' .format(len(tools_found), plugin_path, tools_found[-1])) tool_found = tools_found[-1] else: tool_found = tools_found[0] tool_loader = loader.find_loader(tool_found[0]) # Check if DCC specific implementation for plugin exists dcc_path = '{}.dccs.{}'.format(plugin_name, dcc.get_name()) dcc_loader = None dcc_config = None try: dcc_loader = loader.find_loader(dcc_path) except ImportError: pass tool_config_dict = tool_found[2].config_dict( file_name=plugin_path) or dict() tool_id = tool_config_dict['id'] _tool_name = tool_config_dict['name'] tool_icon = tool_config_dict['icon'] tool_config_name = plugin_name.replace('.', '-') tool_config = configs.get_config(config_name=tool_config_name, package_name=pkg_name, root_package_name=root_pkg_name, environment=environment, config_dict=config_dict, extra_data=tool_config_dict) if dcc_loader: dcc_path = dcc_loader.fullname dcc_config = configs.get_config(config_name=dcc_path.replace( '.', '-'), package_name=pkg_name, environment=environment, config_dict=config_dict) if not dcc_config.get_path(): dcc_config = None # Register resources def_resources_path = os.path.join(plugin_path, 'resources') # resources_path = plugin_config.data.get('resources_path', def_resources_path) resources_path = tool_config_dict.get('resources_path', None) if not resources_path or not os.path.isdir(resources_path): resources_path = def_resources_path if os.path.isdir(resources_path): resources.register_resource(resources_path, key='tools') else: pass # tp.logger.debug('No resources directory found for plugin "{}" ...'.format(_plugin_name)) # Register DCC specific resources if dcc_loader and dcc_config: def_resources_path = os.path.join(dcc_loader.filename, 'resources') resources_path = dcc_config.data.get('resources_path', def_resources_path) if not resources_path or not os.path.isdir(resources_path): resources_path = def_resources_path if os.path.isdir(resources_path): resources.register_resource(resources_path, key='plugins') else: pass # tp.logger.debug('No resources directory found for plugin "{}" ...'.format(_plugin_name)) # Create tool loggers directory default_logger_dir = os.path.normpath( os.path.join(os.path.expanduser('~'), 'tpDcc', 'logs', 'tools')) default_logging_config = os.path.join(plugin_path, '__logging__.ini') logger_dir = tool_config_dict.get('logger_dir', default_logger_dir) if not os.path.isdir(logger_dir): os.makedirs(logger_dir) logging_file = tool_config_dict.get('logging_file', default_logging_config) tool_package = plugin_name tool_package_path = plugin_path dcc_package = None dcc_package_path = None if dcc_loader: dcc_package = dcc_loader.fullname if python.is_python2( ) else dcc_loader.loader.path dcc_package_path = dcc_loader.filename if python.is_python2( ) else dcc_loader.loader.name self._plugins[pkg_name][tool_id] = { 'name': _tool_name, 'icon': tool_icon, 'package_name': pkg_name, 'loader': package_loader, 'config': tool_config, 'config_dict': tool_config_dict, 'plugin_loader': tool_loader, 'plugin_package': tool_package, 'plugin_package_path': tool_package_path, 'version': tool_found[1] if tool_found[1] is not None else "0.0.0", 'dcc_loader': dcc_loader, 'dcc_package': dcc_package, 'dcc_package_path': dcc_package_path, 'dcc_config': dcc_config, 'logging_file': logging_file, 'plugin_instance': None } LOGGER.info('Tool "{}" registered successfully!'.format(plugin_name)) return True
def get_tool_by_id(self, tool_id, package_name=None, dev=False, *args, **kwargs): """ Launches tool of a specific package by its ID :param tool_id: str, tool ID :param package_name: str, str :param dev: bool :param args: tuple, arguments to pass to the tool execute function :param kwargs: dict, keyword arguments to pas to the tool execute function :return: DccTool or None, executed tool instance """ if not package_name: package_name = tool_id.replace('.', '-').split('-')[0] if package_name not in self._plugins: LOGGER.warning( 'Impossible to load tool by id: package "{}" is not registered!' .format(package_name)) return None if tool_id in self._plugins[package_name]: tool_inst = self._plugins[package_name][tool_id].get( 'tool_instance', None) if tool_inst: return tool_inst tool_to_run = None for plugin_id in self._plugins[package_name].keys(): tool_path = self._plugins[package_name][plugin_id][ 'plugin_package'] sec_path = tool_path.replace('.', '-') if sec_path == tool_path or sec_path == tool_id: tool_to_run = tool_id break else: tool_name = tool_path.split('.')[-1] if tool_name == tool_path: tool_to_run = tool_id break if not tool_to_run or tool_to_run not in self._plugins[package_name]: LOGGER.warning('Tool "{}" is not registered!'.format(tool_id)) return None tool_loader = self._plugins[package_name][tool_to_run]['loader'] pkg_loader = self._plugins[package_name][tool_to_run]['loader'] tool_config = self._plugins[package_name][tool_to_run]['config'] tool_fullname = tool_loader.fullname if python.is_python2( ) else tool_loader.loader.name tool_version = self._plugins[package_name][tool_to_run]['version'] pkg_name = pkg_loader.filename if python.is_python2( ) else os.path.dirname(pkg_loader.loader.path) pkg_path = pkg_loader.fullname if python.is_python2( ) else pkg_loader.loader.name tool_found = None for sub_module in pkgutil.walk_packages( [self._plugins[package_name][tool_to_run]['plugin_package_path']]): tool_importer, sub_module_name, _ = sub_module mod = tool_importer.find_module(sub_module_name).load_module( sub_module_name) for cname, obj in inspect.getmembers(mod, inspect.isclass): if issubclass(obj, tool.DccTool): obj.FILE_NAME = pkg_name obj.FULL_NAME = pkg_path tool_found = obj break if tool_found: break if not tool_found: LOGGER.error( "Error while launching tool: {}".format(tool_fullname)) return None # if dcc_loader: # tool_config = dcc_config tool_settings = self.get_tool_settings_file(tool_id) if not tool_settings.has_setting('theme'): tool_settings.set('theme', 'default') tool_settings.setFallbacksEnabled(False) tool_inst = tool_found(self, config=tool_config, settings=tool_settings, dev=dev, *args, **kwargs) tool_inst.ID = tool_id tool_inst.VERSION = tool_version tool_inst.AUTHOR = tool_inst.config_dict().get('creator', None) tool_inst.PACKAGE = package_name self._plugins[package_name][tool_id]['tool_instance'] = tool_inst # self._plugins[package_name][plugin_id]['tool_instance'] = tool_inst return tool_inst
def _create_editors(self): """ Internal function that creates the editors that should be used by tagger Overrides to add custom editors """ if python.is_python2(): import pkgutil as loader else: import importlib as loader editors_modules = self.config.get('editors_module') if not editors_modules: LOGGER.warning( 'No core editors module specified in artellapipe.tools.tagger configuration file!' ) return False available_editors = self.config.get('available_editors') if not available_editors: LOGGER.warning( 'No available editors defined in artellapipe.tools.tagger configuration file!' ) return False LOGGER.info('Loading Available Editors: {}'.format(available_editors)) modules_to_register = dict() all_modules = [editors_modules] extra_editors_modules = self.config.get('extra_editors_modules') if extra_editors_modules: all_modules.extend(extra_editors_modules) for module in all_modules: try: pkg_loader = loader.find_loader(module) except Exception: continue if pkg_loader is not None: modules_to_register[module] = pkg_loader editors_found = dict() for module_path, pkg_loader in modules_to_register.items(): for sub_module in loader.walk_packages([pkg_loader.filename]): importer, sub_module_name, _ = sub_module qname = pkg_loader.fullname + '.' + sub_module_name editors_found[qname] = list() try: mod = importer.find_module(sub_module_name).load_module( sub_module_name) except Exception as exc: LOGGER.warning( 'Impossible to import tagger editors from: "{}" | {}'. format(module_path, exc)) continue for cname, obj in inspect.getmembers(mod, inspect.isclass): if issubclass(obj, taggereditor.TaggerEditor): if not hasattr(obj, 'EDITOR_TYPE') or not obj.EDITOR_TYPE: LOGGER.warning( 'Editor "{}" has not EDITOR_TYPE defined') continue editors_found[qname].append(obj) loaded_editors = list() for available_editor in available_editors: if available_editor in loaded_editors: LOGGER.warning( 'Editor "{}" of type "{}" is already loaded. Skipping ...'. format(editor_class, editor_type)) continue for editor_classes in editors_found.values(): if not editor_classes: continue for editor_class in editor_classes: editor_type = editor_class.EDITOR_TYPE if editor_type == available_editor: new_editor = editor_class(project=self._project) self.add_editor(new_editor) loaded_editors.append(editor_type) not_loaded_editors = list() for available_editor in available_editors: if available_editor not in loaded_editors: not_loaded_editors.append(available_editor) if not_loaded_editors: LOGGER.warning( 'Was not possible to load following tag editors: {}!'.format( not_loaded_editors))
__author__ = "Tomas Poveda" __license__ = "MIT" __maintainer__ = "Tomas Poveda" __email__ = "*****@*****.**" import os import logging import inspect import traceback import importlib from collections import OrderedDict import tpDcc as tp from tpDcc.libs.python import python, decorators, strings, path as path_utils if python.is_python2(): import pkgutil as loader else: import importlib as loader import artellapipe from artellapipe.utils import exceptions from artellapipe.core import defines from artellapipe.libs.artella.core import artellalib, artellaclasses LOGGER = logging.getLogger('artellapipe') class AssetsManager(object): _assets = list()
def load_plugin(self, pkg_name, pkg_loaders, environment, root_pkg_name=None, config_dict=None, load=True): """ Implements load_plugin function Registers a plugin instance to the manager :param pkg_name: str :param pkg_loaders: plugin instance to register :param environment: :param root_pkg_name: :param config_dict: :param load: :return: Plugin """ from tpDcc.managers import configs if not pkg_loaders: return False package_loader = pkg_loaders[0] if isinstance(pkg_loaders, (list, tuple)) else pkg_loaders if not package_loader: return False if hasattr(package_loader, 'loader'): if not package_loader.loader: return False plugin_path = package_loader.filename if python.is_python2( ) else os.path.dirname(package_loader.loader.path) plugin_name = package_loader.fullname if python.is_python2( ) else package_loader.loader.name if not config_dict: config_dict = dict() config_dict.update({ 'join': os.path.join, 'user': os.path.expanduser('~'), 'filename': plugin_path, 'fullname': plugin_name, 'root': path_utils.clean_path(plugin_path) }) if pkg_name not in self._plugins: self._plugins[pkg_name] = dict() libs_found = list() version_found = None init_fn = None mods_found = list() # packages_to_walk = [plugin_path] if python.is_python2() else [os.path.dirname(plugin_path)] for module_path in modules.iterate_modules(plugin_path, skip_inits=False, recursive=False): module_dot_path = modules.convert_to_dotted_path(module_path) try: mod = modules.import_module(module_dot_path) if not mod: continue except Exception: continue if module_dot_path.endswith('__version__') and hasattr( mod, 'get_version') and callable(mod.get_version): if version_found: LOGGER.warning( 'Already found version: "{}" for "{}"'.format( version_found, plugin_name)) else: version_found = getattr(mod, 'get_version')() if not init_fn and module_dot_path.endswith('loader') and hasattr( mod, 'init') and callable(mod.init): init_fn = mod.init mod.LOADED = load mods_found.append(mod) for mod in mods_found: for cname, obj in inspect.getmembers(mod, inspect.isclass): for interface in self._interfaces: if issubclass(obj, interface): lib_config_dict = obj.config_dict( file_name=plugin_path) or dict() if not lib_config_dict: continue lib_id = lib_config_dict.get('id', None) tool_config_name = lib_config_dict.get('name', None) if not lib_id: LOGGER.warning( 'Impossible to register library "{}" because its ID is not defined!' .format(lib_id)) continue if not tool_config_name: LOGGER.warning( 'Impossible to register library "{}" because its name is not defined!' .format(tool_config_name)) continue if root_pkg_name and root_pkg_name in self._plugins and lib_id in self._plugins[ root_pkg_name]: LOGGER.warning( 'Impossible to register library "{}" because its ID "{}" its already defined!' .format(tool_config_name, lib_id)) continue if not version_found: version_found = '0.0.0' obj.VERSION = version_found obj.FILE_NAME = plugin_path obj.FULL_NAME = plugin_name libs_found.append((module_path, version_found, obj)) version_found = True break if not libs_found: LOGGER.warning( 'No libraries found in module "{}". Skipping ...'.format( plugin_path)) return False if len(libs_found) > 1: LOGGER.warning( 'Multiple libraries found ({}) in module "{}". Loading first one. {} ...' .format(len(libs_found), plugin_path, libs_found[-1])) lib_found = libs_found[-1] else: lib_found = libs_found[0] lib_loader = modules.convert_to_dotted_path(lib_found[0]) lib_loader = loader.find_loader(lib_loader) # Check if DCC specific implementation for plugin exists dcc_path = '{}.dccs.{}'.format(plugin_name, dcc.get_name()) dcc_loader = None dcc_config = None try: dcc_loader = loader.find_loader(dcc_path) except ImportError: pass lib_config_dict = lib_found[2].config_dict( file_name=plugin_path) or dict() lib_id = lib_config_dict['id'] _tool_name = lib_config_dict['name'] tool_config_name = plugin_name.replace('.', '-') lib_config = configs.get_config(config_name=tool_config_name, package_name=pkg_name, root_package_name=root_pkg_name, environment=environment, config_dict=config_dict, extra_data=lib_config_dict) if dcc_loader: dcc_path = dcc_loader.fullname dcc_config = configs.get_config(config_name=dcc_path.replace( '.', '-'), package_name=pkg_name, environment=environment, config_dict=config_dict) if not dcc_config.get_path(): dcc_config = None # Register resources def_resources_path = os.path.join(plugin_path, 'resources') # resources_path = plugin_config.data.get('resources_path', def_resources_path) resources_path = lib_config_dict.get('resources_path', None) if not resources_path or not os.path.isdir(resources_path): resources_path = def_resources_path if os.path.isdir(resources_path): resources.register_resource(resources_path, key='tools') else: pass # tp.logger.debug('No resources directory found for plugin "{}" ...'.format(_plugin_name)) # Register DCC specific resources if dcc_loader and dcc_config: def_resources_path = os.path.join(dcc_loader.filename, 'resources') resources_path = dcc_config.data.get('resources_path', def_resources_path) if not resources_path or not os.path.isdir(resources_path): resources_path = def_resources_path if os.path.isdir(resources_path): resources.register_resource(resources_path, key='plugins') else: pass # tp.logger.debug('No resources directory found for plugin "{}" ...'.format(_plugin_name)) # Create lib loggers directory default_logger_dir = os.path.normpath( os.path.join(os.path.expanduser('~'), 'tpDcc', 'logs', 'libs')) default_logging_config = os.path.join(plugin_path, '__logging__.ini') logger_dir = lib_config_dict.get('logger_dir', default_logger_dir) if not os.path.isdir(logger_dir): os.makedirs(logger_dir) logging_file = lib_config_dict.get('logging_file', default_logging_config) lib_package = plugin_name lib_package_path = plugin_path dcc_package = None dcc_package_path = None if dcc_loader: dcc_package = dcc_loader.fullname if python.is_python2( ) else dcc_loader.loader.path dcc_package_path = dcc_loader.filename if python.is_python2( ) else dcc_loader.loader.name self._plugins[pkg_name][lib_id] = { 'name': _tool_name, 'package_name': pkg_name, 'loader': package_loader, 'config': lib_config, 'config_dict': lib_config_dict, 'plugin_loader': lib_loader, 'plugin_package': lib_package, 'plugin_package_path': lib_package_path, 'version': lib_found[1] if lib_found[1] is not None else "0.0.0", 'dcc_loader': dcc_loader, 'dcc_package': dcc_package, 'dcc_package_path': dcc_package_path, 'dcc_config': dcc_config, 'logging_file': logging_file, 'plugin_instance': None } if init_fn: try: dev = True if environment == 'development' else False init_fn(dev=dev) LOGGER.info( 'Library "{}" registered and initialized successfully!'. format(plugin_name)) except Exception: LOGGER.warning( 'Library "{}" registered successfully but its initialization failed: {}' .format(plugin_name, traceback.format_exc())) else: LOGGER.info( 'Library "{}" registered successfully!'.format(plugin_name)) return True