Source code for nose2.plugins.attrib

import logging
from unittest import TestSuite

from import Plugin

log = logging.getLogger(__name__)
undefined = object()

[docs]class AttributeSelector(Plugin): """Filter tests by attribute""" def __init__(self): self.attribs = [] self.eval_attribs = [] self.addArgument( self.attribs, "A", "attribute", "Select tests with matching attribute" ) self.addArgument( self.eval_attribs, "E", "eval-attribute", "Select tests for whose attributes the " "given Python expression evaluates to ``True``", )
[docs] def handleArgs(self, args): """Register if any attribs defined""" if self.attribs or self.eval_attribs: self.register()
[docs] def moduleLoadedSuite(self, event): """Filter event.suite by specified attributes""" log.debug("Attribute selector attribs %s/%s", self.attribs, self.eval_attribs) attribs = [] for attr in self.eval_attribs: def eval_in_context(expr, obj): try: return eval(expr, None, ContextHelper(obj)) except Exception as e: log.warning("%s raised exception %s with test %s", expr, e, obj) return False attribs.append([(attr, eval_in_context)]) for attr in self.attribs: # all attributes within an attribute group must match attr_group = [] for attrib in attr.strip().split(","): # don't die on trailing comma if not attrib: continue items = attrib.split("=", 1) if len(items) > 1: # "name=value" # -> 'str( == value' must be True key, value = items else: key = items[0] if key[0] == "!": # "!name" # 'bool(' must be False key = key[1:] value = False else: # "name" # -> 'bool(' must be True value = True attr_group.append((key, value)) attribs.append(attr_group) if not attribs: return event.suite = self.filterSuite(event.suite, attribs)
def filterSuite(self, suite, attribs): # FIXME probably need to copy or something to allow suites w/custom attrs to # work or iter and remove instead of recreating new_suite = suite.__class__() for test in suite: if isinstance(test, TestSuite): new_suite.addTest(self.filterSuite(test, attribs)) elif self.validateAttrib(test, attribs): new_suite.addTest(test) return new_suite def validateAttrib(self, test, attribs): any_ = False for group in attribs: match = True for key, value in group: neg = False if key.startswith("!"): neg, key = True, key[1:] obj_value = _get_attr(test, key) if callable(value): if not value(key, test): match = False break elif value is True: # value must exist and be True if not bool(obj_value): match = False break elif value is False: # value must not exist or be False if bool(obj_value): match = False break elif type(obj_value) in (list, tuple): # value must be found in the list attribute found = str(value).lower() in [str(x).lower() for x in obj_value] if found and neg: match = False break elif not found and not neg: match = False break else: # value must match, convert to string and compare if ( value != obj_value and str(value).lower() != str(obj_value).lower() ): match = False break any_ = any_ or match return any_
# helpers def _get_attr(test, key): # FIXME for vals that are lists (or just mutable?), combine all levels val = getattr(test, key, undefined) if val is not undefined: return val if hasattr(test, "_testFunc"): val = getattr(test._testFunc, key, undefined) if val is not undefined: return val elif hasattr(test, "_testMethodName"): # testclasses support if test.__class__.__name__ == "_MethodTestCase": meth = getattr(test.obj, test.method, undefined) else: meth = getattr(test, test._testMethodName, undefined) if meth is not undefined: val = getattr(meth, key, undefined) if val is not undefined: return val class ContextHelper: def __init__(self, obj): self.obj = obj def __getitem__(self, name): return _get_attr(self.obj, name)