Source code for tools

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

""" Module __init__.py: This module acts to import all files in subdirectories
 to sys.modules """

import inspect
import os
import logging
import traceback
import sys

from stkMariTools.lib.ui_utils import MariToolsMenuItem

# Use importlib if detected Python 2.7 or later
if sys.version_info >= (2,7):
    _use_legacy_libraries = False
    import importlib

else:
    _use_legacy_libraries = True


[docs]def import_submodules(): """ This method will import all submodules from the ./tools folder into the module namespace. It will also attempt to load and register any valid Mari Tools plugins that are a subclass of ``MariToolsMenuItem``. :return: ``None`` """ logger = logging.getLogger(__name__) # Grab all modules in subdirectories recursively modules = [] # Normalize the base path basePath = os.path.dirname(os.path.abspath(__file__)) logger.debug('Searching directory:\n{0}\nrecursively for modules...\n' .format(basePath)) for root, dirs, filenames in os.walk(basePath): for filename in filenames: # Only grab .py files and not files like __init__.py if filename.endswith('.py') and not filename.startswith('__'): # Filter out broken symlinks and directories called 'dir.py/' if os.path.isfile(os.path.join(root, filename)): # todo: Check for duplicate filenames and deal with them in the namespace modules.append((filename, os.path.join(root, filename))) # todo: check if importing into __all__ is really needed # Define all module names to be in the package namespace # __all__ = [os.path.basename(module[0])[:-3] for module in modules] # # logger.debug('Successfully set the following modules to {0} namespace: \n{1}\n' # .format(__name__, __all__)) for module in modules: try: logger.info('Inspecting module: {0} ...'.format(module[0])) # Format module namespaces for absolute import parent_module_path = os.path.abspath(os.path.dirname(module[1])) parent_module_namespace = parent_module_path.split('stkMariTools')[-1].split(os.path.sep) parent_module_namespace[0] = 'stkMariTools' parent_module_namespace = '.'.join(parent_module_namespace) module_namespace = module[1].split('stkMariTools')[-1].split(os.path.sep) module_namespace[0] = 'stkMariTools' module_namespace[-1] = os.path.splitext(module_namespace[-1])[0] module_namespace = '.'.join(module_namespace) logger.debug('Formatted parent namespace as: {0} and module namespace as: {1} ...' .format(parent_module_namespace, module_namespace)) # Attempt to import the package # If using older than Python 2.7, use legacy import method to handle # the absolute import, otherwise use newer importlib module if _use_legacy_libraries: try: # todo: check if using importlib or __import__ is ultimately the best solution here # Use __import__ over imp.load_source because imp does not # automatically import parent packages, it only creates the # parent namespace objects; submodules will then fail to # import packages that rely on other submodules loaded_submodule = __import__(module_namespace, fromlist=['']) except ImportError: logger.error('### Failed to import module!!!\n{0}' .format(traceback.print_exc())) continue else: try: importlib.import_module( name=parent_module_namespace, package=module[1] ) loaded_submodule = importlib.import_module( name=module_namespace, package=module[1] ) except ImportError: logger.error('### Failed to import module!!!\n{0}' .format(traceback.print_exc())) continue # Get all class members from imported module in order to check against class_members = inspect.getmembers(loaded_submodule, inspect.isclass) # Filter out class members which are not defined within the module itself class_members = filter( lambda x:inspect.getmodule(x[1])==loaded_submodule, class_members ) # Check if valid type of subclass for class_member in class_members: # Check if the class member is a valid subclass and if it is # actually defined within the module if not issubclass(class_member[1], MariToolsMenuItem): # Skip this class member continue # Get the Method Resolution Order (shows class inheritance) base_class = inspect.getmro(class_member[1])[-2] if base_class == MariToolsMenuItem: logger.debug('Valid base class for: {0} detected, attempting ' 'to register plugin...' .format(module[0])) assert isinstance(class_member, tuple), \ '### {0} is an invalid tuple object!!!' # Create a new instance from the class type plugin_instance = class_member[1]() # Call the pre-defined function in order to implement the plugin try: plugin_instance.registerMariToolsPlugin() logger.info('Successfully registered the following menuItem plugin: ' '{0}!\n\n------\n\n' .format(module[0])) except AttributeError: logger.error('### {0} does not have the registerMariToolsPlugin() ' 'method implemented!!!\n{1}' .format(traceback.print_exc())) except RuntimeWarning: logger.warning('# Absolute import was handled incorrectly!\n{0}' .format(traceback.print_exc())) continue except ImportError: logger.error('### Could not find module!!!\n{0}' .format(traceback.print_exc())) continue except AttributeError: logger.debug('Module does not have required registerMariToolsPlugin() ' 'method implemented, skipping...\n{0}\n{1}' .format(module[1], traceback.print_exc())) continue except Exception: logger.error('### Importing tools modules failed!!!\n{0}' .format(traceback.print_exc())) continue