def _dependent_names(descriptor): # print "analyze_dependent_names: %s" % descriptor.name for imp in descriptor.context.get("imports"): # print " import: %s" % str(imp) # name is the fully qualified name name, level = imp[1], imp[2] assert name and level is not None modulename = name if level == 0: # 0 means only perform absolute imports modulename = _modulename(name) elif level == -1: # -1 which indicates both absolute and relative imports # will be attempted # Implicit relative import if descriptor.package_name: modulename = ".".join((descriptor.package_name, name)) if modulename not in descriptors and "." in name: modulename = _modulename(modulename) # Implicit relative import failed if modulename not in descriptors: modulename = _modulename(name) else: # The import declaration refers a relative package. if not descriptor.package_name: continue modulename = resolve_relative_modulename(name, descriptor.package_name, level) modulename = _modulename(modulename) if modulename in descriptors: yield modulename
def has_subclass(module_descriptor, baseclass): """ Return ``True`` if the module has a class derived from *baseclass* """ # We can't use ``unittest.TestLoader`` to loading tests, # bacause ``TestLoader`` imports (execute) module code. # If imported/executed module have a statement such as # ``sys.exit()``, ...program exit! if not isinstance(baseclass, (type, types.ClassType)): raise TypeError( "The baseclass argument must be instance of type or class, " "but was instance of %s" % type(baseclass)) modcode = module_descriptor.module_code assert modcode # How to check unittest.TestCase # ============================================ # 1. For all class definition in module code # 2. Check class is derived from base class(s) # 3. Check base class(s) is imported from another module # 4. Load base class(s) from that module # Notes: Assume the module contains base class does not have # a dangerous code such as ``sys.exit``. # 5. Check loaded class is *baseclass* or its subclass # Construct imported symbols. # This is used in phase 3. symbols = dict([(imp[0], imp) for imp in modcode.context['imports']]) # 1. For all class definition in module code for klass in modcode.context['classdefs']: # 2. Check class is derived from base class(s) bases = klass[1] if not bases: continue # 3. Check base class(s) is imported from another module for base in bases: # Search imported symbol that is class name or module name if '.' in base: names = list(split_module_name(base)) else: names = [base] import_ = symbols.get(names[0]) if import_ is None: # Not an imported base class continue # Convert a name to a qualified module name # # 1. Resolve import alias if exists # 2. Qualify name as full module name # 3. Resolve relative module name # level = import_[2] names[0] = import_[1] fqn = '.'.join(names) fqn = resolve_relative_modulename(fqn, modcode.package_name, level) assert '.' in fqn, "fqn must be a qualified module fqn" LOGGER.debug("'%s' is derived from '%s'" % (module_descriptor.name, fqn)) try: try: klass = utils.import_component(fqn) except ImportError: if level == -1 and modcode.package_name: # The qualified name may be relative to current package. fqn = '.'.join((modcode.package_name, fqn)) klass = utils.import_component(fqn) else: raise except (ImportError, AttributeError): LOGGER.warn("Exception occurred " "while importing component '%s'" % fqn, exc_info=True) else: # 5. Check loaded class is specified class or its subclass if isinstance(klass, (type, types.ClassType)) and \ issubclass(klass, baseclass): return True return False
def has_subclass(module_descriptor, baseclass): """ Return ``True`` if the module has a class derived from *baseclass* """ # We can't use ``unittest.TestLoader`` to loading tests, # bacause ``TestLoader`` imports (execute) module code. # If imported/executed module have a statement such as # ``sys.exit()``, ...program exit! if not isinstance(baseclass, (type, types.ClassType)): raise TypeError( "The baseclass argument must be instance of type or class, " "but was instance of %s" % type(baseclass)) modcode = module_descriptor.module_code assert modcode # How to check unittest.TestCase # ============================================ # 1. For all class definition in module code # 2. Check class is derived from base class(s) # 3. Check base class(s) is imported from another module # 4. Load base class(s) from that module # Notes: Assume the module contains base class does not have # a dangerous code such as ``sys.exit``. # 5. Check loaded class is *baseclass* or its subclass # Construct imported symbols. # This is used in phase 3. symbols = dict([(imp[0], imp) for imp in modcode.context['imports']]) # 1. For all class definition in module code for klass in modcode.context['classdefs']: # 2. Check class is derived from base class(s) bases = klass[1] if not bases: continue # 3. Check base class(s) is imported from another module for base in bases: # Search imported symbol that is class name or module name symbol = base if '.' in symbol: symbol = split_module_name(symbol)[0] import_ = symbols.get(symbol) if import_ is None: continue # Convert name to a qualified module name name, level = base, import_[2] parent = split_module_name(import_[1])[0] if parent: name = '.'.join((parent, name)) name = resolve_relative_modulename( name, modcode.package_name, level) assert '.' in name, "name must be a qualified module name" LOGGER.debug("'%s' is derived from '%s'" % (base, name)) try: klass = utils.import_component(name) except ImportError: klass = None exc = sys.exc_info()[:] if level == -1 and modcode.package_name: # Try to resolve a name as relative module name. try: name2 = '.'.join((modcode.package_name, name)) klass = utils.import_component(name2) except: LOGGER.warn( "Exception occurred while importing module '%s'" % name2, exc_info=True) if not klass: LOGGER.warn( "Exception occurred while importing module '%s'" % name, exc_info=exc) # Make sure to delete the traceback to avoid creating cycles. del exc except AttributeError: LOGGER.warn( "Exception occurred while importing module '%s'" % name, exc_info=True) else: # 5. Check loaded class is specified class or its subclass if isinstance(klass, (type, types.ClassType)) and \ issubclass(klass, baseclass): return True return False