How to use is_matching_klass method in avocado

Best Python code snippet using avocado_python

safeloader.py

Source:safeloader.py Github

copy

Full Screen

...58 # on the type of import, it can be also be $path/$module.59 self.imported_objects = {}60 with open(self.path) as source_file:61 self.mod = ast.parse(source_file.read(), self.path)62 def is_matching_klass(self, klass):63 """64 Detect whether given class directly defines itself as <module>.<klass>65 It can either be a <klass> that inherits from a test "symbol", like:66 ```class FooTest(Test)```67 Or from an <module>.<klass> symbol, like in:68 ```class FooTest(avocado.Test)```69 :type klass: :class:`_ast.ClassDef`70 :rtype: bool71 """72 # Is it inherited from Test? 'class FooTest(Test):'73 if self.klass_imports:74 base_ids = [base.id for base in klass.bases75 if isinstance(base, ast.Name)]76 # Looking for a 'class FooTest(Test):'77 if not self.klass_imports.isdisjoint(base_ids):78 return True79 # Is it inherited from avocado.Test? 'class FooTest(avocado.Test):'80 if self.mod_imports:81 for base in klass.bases:82 if not isinstance(base, ast.Attribute):83 # Check only 'module.Class' bases84 continue85 cls_module = base.value.id86 cls_name = base.attr87 if cls_module in self.mod_imports and cls_name == self.klass:88 return True89 return False90 def add_imported_object(self, statement):91 """92 Keeps track of objects names and importable entities93 """94 path = os.path.abspath(os.path.dirname(self.path))95 if getattr(statement, 'module', None) is not None:96 module_path = statement.module.replace('.', os.path.sep)97 path = os.path.join(path, module_path)98 else:99 # Module has no name, its path is relative to the directory100 # structure101 level = getattr(statement, 'level', 0)102 for _ in range(level - 1):103 path = os.path.dirname(path)104 for name in statement.names:105 full_path = os.path.join(path, name.name.replace('.', os.path.sep))106 final_name = self._get_name_from_alias_statement(name)107 self.imported_objects[final_name] = full_path108 @staticmethod109 def _get_name_from_alias_statement(alias):110 """Returns the aliased name or original one."""111 return alias.asname if alias.asname else alias.name112 def _handle_import_from(self, statement):113 self.add_imported_object(statement)114 if statement.module != self.module:115 return116 name = statement_import_as(statement).get(self.klass, None)117 if name is not None:118 self.klass_imports.add(name)119 @staticmethod120 def _all_module_level_names(full_module_name):121 result = []122 components = full_module_name.split(".")[:-1]123 for topmost in range(len(components)):124 result.append(".".join(components[-topmost:]))125 components.pop()126 return result127 def _handle_import(self, statement):128 self.add_imported_object(statement)129 imported_as = statement_import_as(statement)130 name = imported_as.get(self.module, None)131 if name is not None:132 self.mod_imports.add(name)133 for as_name in imported_as.values():134 for mod_name in self._all_module_level_names(as_name):135 if mod_name == self.module:136 self.mod_imports.add(mod_name)137 def iter_classes(self):138 """139 Iterate through classes and keep track of imported avocado statements140 """141 for statement in self.mod.body:142 # Looking for a 'from <module> import <klass>'143 if isinstance(statement, ast.ImportFrom):144 self._handle_import_from(statement)145 # Looking for a 'import <module>'146 elif isinstance(statement, ast.Import):147 self._handle_import(statement)148 # Looking for a 'class Anything(anything):'149 elif isinstance(statement, ast.ClassDef):150 yield statement151def statement_import_as(statement):152 """153 Returns a mapping of imported module names whether using aliases or not154 :param statement: an AST import statement155 :type statement: ast.Import156 :returns: a mapping of names {<realname>: <alias>} of modules imported157 :rtype: dict158 """159 result = {}160 for name in statement.names:161 if name.asname is not None:162 result[name.name] = name.asname163 else:164 result[name.name] = name.name165 return result166def modules_imported_as(module):167 """168 Returns a mapping of imported module names whether using aliases or not169 The goal of this utility function is to return the name of the import170 as used in the rest of the module, whether an aliased import was used171 or not.172 For code such as:173 >>> import foo as bar174 This function should return {"foo": "bar"}175 And for code such as:176 >>> import foo177 It should return {"foo": "foo"}178 Please note that only global level imports are looked at. If there are179 imports defined, say, inside functions or class definitions, they will180 not be seen by this function.181 :param module: module, as parsed by :func:`ast.parse`182 :type module: :class:`_ast.Module`183 :returns: a mapping of names {<realname>: <alias>} of modules imported184 :rtype: dict185 """186 result = {}187 for statement in module.body:188 if isinstance(statement, ast.Import):189 result.update(statement_import_as(statement))190 return result191#: Gets the docstring directive value from a string. Used to tweak192#: test behavior in various ways193DOCSTRING_DIRECTIVE_RE_RAW = r'\s*:avocado:[ \t]+(([a-zA-Z0-9]+?[a-zA-Z0-9_:,\=\-\.]*)|(r[a-zA-Z0-9]+?[a-zA-Z0-9_:,\=\{\}\"\-\.\/ ]*))\s*$'194# the RE will match `:avocado: tags=category` or `:avocado: requirements={}`195DOCSTRING_DIRECTIVE_RE = re.compile(DOCSTRING_DIRECTIVE_RE_RAW)196def get_docstring_directives(docstring):197 """198 Returns the values of the avocado docstring directives199 :param docstring: the complete text used as documentation200 :type docstring: str201 :rtype: builtin.list202 """203 result = []204 if docstring is None:205 return result206 for line in docstring.splitlines():207 try:208 match = DOCSTRING_DIRECTIVE_RE.match(line)209 if match:210 result.append(match.groups()[0])211 except TypeError:212 pass213 return result214def check_docstring_directive(docstring, directive):215 """216 Checks if there's a given directive in a given docstring217 :rtype: bool218 """219 return directive in get_docstring_directives(docstring)220def get_docstring_directives_tags(docstring):221 """222 Returns the test categories based on a `:avocado: tags=category`223 docstring224 :rtype: dict225 """226 result = {}227 for item in get_docstring_directives(docstring):228 if item.startswith('tags='):229 _, comma_tags = item.split('tags=', 1)230 for tag in comma_tags.split(','):231 if not tag:232 continue233 if ':' in tag:234 key, val = tag.split(':', 1)235 if key in result:236 result[key].add(val)237 else:238 result[key] = set([val])239 else:240 result[tag] = None241 return result242def get_docstring_directives_requirements(docstring):243 """244 Returns the test requirements from docstring patterns like245 `:avocado: requirement={}`.246 :rtype: list247 """248 requirements = []249 for item in get_docstring_directives(docstring):250 if item.startswith('requirement='):251 _, requirement_str = item.split('requirement=', 1)252 try:253 requirements.append(json.loads(requirement_str))254 except json.decoder.JSONDecodeError:255 # ignore requirement in case of malformed dictionary256 continue257 return requirements258def find_class_and_methods(path, method_pattern=None, base_class=None):259 """260 Attempts to find methods names from a given Python source file261 :param path: path to a Python source code file262 :type path: str263 :param method_pattern: compiled regex to match against method name264 :param base_class: only consider classes that inherit from a given265 base class (or classes that inherit from any class266 if None is given)267 :type base_class: str or None268 :returns: an ordered dictionary with classes as keys and methods as values269 :rtype: collections.OrderedDict270 """271 def inherits_from_base_class(class_statement, base_class_name):272 base_ids = [base.id for base in class_statement.bases273 if hasattr(base, 'id')]274 return base_class_name in base_ids275 result = collections.OrderedDict()276 with open(path) as source_file:277 mod = ast.parse(source_file.read(), path)278 for statement in mod.body:279 if isinstance(statement, ast.ClassDef):280 if base_class is not None:281 if not inherits_from_base_class(statement,282 base_class):283 continue284 if method_pattern is None:285 methods = [st.name for st in statement.body if286 isinstance(st, ast.FunctionDef)]287 methods = data_structures.ordered_list_unique(methods)288 else:289 methods = [st.name for st in statement.body if290 isinstance(st, ast.FunctionDef) and291 method_pattern.match(st.name)]292 methods = data_structures.ordered_list_unique(methods)293 result[statement.name] = methods294 return result295def get_methods_info(statement_body, class_tags, class_requirements):296 """297 Returns information on an Avocado instrumented test method298 """299 methods_info = []300 for st in statement_body:301 if (isinstance(st, ast.FunctionDef) and302 st.name.startswith('test')):303 docstring = ast.get_docstring(st)304 mt_tags = get_docstring_directives_tags(docstring)305 mt_tags.update(class_tags)306 mt_requirements = get_docstring_directives_requirements(docstring)307 mt_requirements.extend(class_requirements)308 methods = [method for method, _, _ in methods_info]309 if st.name not in methods:310 methods_info.append((st.name, mt_tags, mt_requirements))311 return methods_info312def _determine_match_avocado(module, klass, docstring):313 """314 Implements the match check for Avocado Instrumented Tests315 """316 directives = get_docstring_directives(docstring)317 if 'disable' in directives:318 return True319 if 'enable' in directives:320 return True321 if 'recursive' in directives:322 return True323 # Still not decided, try inheritance324 return module.is_matching_klass(klass)325def _extend_test_list(current, new):326 for test in new:327 test_method_name = test[0]328 if test_method_name not in [_[0] for _ in current]:329 current.append(test)330def _examine_class(path, class_name, match, target_module, target_class,331 determine_match):332 """333 Examine a class from a given path334 :param path: path to a Python source code file335 :type path: str336 :param class_name: the specific class to be found337 :type path: str338 :param match: whether the inheritance from <target_module.target_class> has339 been determined or not340 :type match: bool341 :param target_module: the module name under which the target_class lives342 :type target_module: str343 :param target_class: the name of the class that class_name should344 ultimately inherit from345 :type target_class: str346 :param determine_match: a callable that will determine if a match has347 occurred or not348 :type determine_match: function349 :returns: tuple where first item is a list of test methods detected350 for given class; second item is set of class names which351 look like avocado tests but are force-disabled.352 :rtype: tuple353 """354 module = PythonModule(path, target_module, target_class)355 info = []356 disabled = set()357 for klass in module.iter_classes():358 if class_name != klass.name:359 continue360 docstring = ast.get_docstring(klass)361 if match is False:362 match = determine_match(module, klass, docstring)363 info = get_methods_info(klass.body,364 get_docstring_directives_tags(docstring),365 get_docstring_directives_requirements(366 docstring))367 # Getting the list of parents of the current class368 parents = klass.bases369 # From this point we use `_$variable` to name temporary returns370 # from method calls that are to-be-assigned/combined with the371 # existing `$variable`.372 # Searching the parents in the same module373 for parent in parents[:]:374 # Looking for a 'class FooTest(Parent)'375 if not isinstance(parent, ast.Name):376 # 'class FooTest(bar.Bar)' not supported withing377 # a module378 continue379 parent_class = parent.id380 _info, _disabled, _match = _examine_class(module.path, parent_class,381 match, target_module,382 target_class,383 determine_match)384 if _info:385 parents.remove(parent)386 _extend_test_list(info, _info)387 disabled.update(_disabled)388 if _match is not match:389 match = _match390 # If there are parents left to be discovered, they391 # might be in a different module.392 for parent in parents:393 if hasattr(parent, 'value'):394 if hasattr(parent.value, 'id'):395 # We know 'parent.Class' or 'asparent.Class' and need396 # to get path and original_module_name. Class is given397 # by parent definition.398 _parent = module.imported_objects.get(parent.value.id)399 if _parent is None:400 # We can't examine this parent (probably broken401 # module)402 continue403 parent_path = os.path.dirname(_parent)404 parent_module = os.path.basename(_parent)405 parent_class = parent.attr406 else:407 # We don't support multi-level 'parent.parent.Class'408 continue409 else:410 # We only know 'Class' or 'AsClass' and need to get411 # path, module and original class_name412 _parent = module.imported_objects.get(parent.id)413 if _parent is None:414 # We can't examine this parent (probably broken415 # module)416 continue417 parent_path, parent_module, parent_class = (418 _parent.rsplit(os.path.sep, 2))419 modules_paths = [parent_path,420 os.path.dirname(module.path)] + sys.path421 found_spec = PathFinder.find_spec(parent_module, modules_paths)422 if found_spec is not None:423 _info, _disabled, _match = _examine_class(found_spec.origin,424 parent_class,425 match,426 target_module,427 target_class,428 _determine_match_avocado)429 if _info:430 _extend_test_list(info, _info)431 disabled.update(_disabled)432 if _match is not match:433 match = _match434 return info, disabled, match435def find_python_tests(module_name, class_name, determine_match, path):436 """437 Attempts to find Python tests from source files438 A Python test in this context is a method within a specific type439 of class (or that inherits from a specific class).440 :param module_name: the name of the module from which a class should441 have come from442 :type module_name: str443 :param class_name: the name of the class that is considered to contain444 test methods445 :type class_name: str446 :type determine_match: a callable that will determine if a given module447 and class is contains valid Python tests448 :type determine_match: function449 :param path: path to a Python source code file450 :type path: str451 :returns: tuple where first item is dict with class name and additional452 info such as method names and tags; the second item is453 set of class names which look like Python tests but have been454 forcefully disabled.455 :rtype: tuple456 """457 module = PythonModule(path, module_name, class_name)458 # The resulting test classes459 result = collections.OrderedDict()460 disabled = set()461 for klass in module.iter_classes():462 docstring = ast.get_docstring(klass)463 # Looking for a class that has in the docstring either464 # ":avocado: enable" or ":avocado: disable465 if check_docstring_directive(docstring, 'disable'):466 disabled.add(klass.name)467 continue468 if check_docstring_directive(docstring, 'enable'):469 info = get_methods_info(klass.body,470 get_docstring_directives_tags(docstring),471 get_docstring_directives_requirements(472 docstring))473 result[klass.name] = info474 continue475 # From this point onwards we want to do recursive discovery, but476 # for now we don't know whether it is avocado.Test inherited477 # (Ifs are optimized for readability, not speed)478 # If "recursive" tag is specified, it is forced as test479 if check_docstring_directive(docstring, 'recursive'):480 is_valid_test = True481 else:482 is_valid_test = module.is_matching_klass(klass)483 info = get_methods_info(klass.body,484 get_docstring_directives_tags(docstring),485 get_docstring_directives_requirements(486 docstring))487 _disabled = set()488 # Getting the list of parents of the current class489 parents = klass.bases490 # Searching the parents in the same module491 for parent in parents[:]:492 # Looking for a 'class FooTest(Parent)'493 if not isinstance(parent, ast.Name):494 # 'class FooTest(bar.Bar)' not supported withing495 # a module496 continue497 parent_class = parent.id498 _info, _dis, _python_test = _examine_class(module.path,499 parent_class,500 is_valid_test,501 module_name,502 class_name,503 determine_match)504 if _info:505 parents.remove(parent)506 _extend_test_list(info, _info)507 _disabled.update(_dis)508 if _python_test is not is_valid_test:509 is_valid_test = _python_test510 # If there are parents left to be discovered, they511 # might be in a different module.512 for parent in parents:513 if hasattr(parent, 'value'):514 if hasattr(parent.value, 'id'):515 # We know 'parent.Class' or 'asparent.Class' and need516 # to get path and original_module_name. Class is given517 # by parent definition.518 _parent = module.imported_objects.get(parent.value.id)519 if _parent is None:520 # We can't examine this parent (probably broken521 # module)522 continue523 parent_path = os.path.dirname(_parent)524 parent_module = os.path.basename(_parent)525 parent_class = parent.attr526 else:527 # We don't support multi-level 'parent.parent.Class'528 continue529 else:530 # We only know 'Class' or 'AsClass' and need to get531 # path, module and original class_name532 _parent = module.imported_objects.get(parent.id)533 if _parent is None:534 # We can't examine this parent (probably broken535 # module)536 continue537 parent_path, parent_module, parent_class = (538 _parent.rsplit(os.path.sep, 2))539 modules_paths = [parent_path,540 os.path.dirname(module.path)] + sys.path541 found_spec = PathFinder.find_spec(parent_module, modules_paths)542 if found_spec is None:543 continue544 _info, _dis, _python_test = _examine_class(found_spec.origin,545 parent_class,546 is_valid_test,547 module_name,548 class_name,549 determine_match)550 if _info:551 info.extend(_info)552 _disabled.update(_dis)553 if _python_test is not is_valid_test:554 is_valid_test = _python_test555 # Only update the results if this was detected as 'avocado.Test'556 if is_valid_test:557 result[klass.name] = info558 disabled.update(_disabled)559 return result, disabled560def find_avocado_tests(path):561 return find_python_tests('avocado', 'Test', _determine_match_avocado, path)562def _determine_match_unittest(module, klass,563 docstring): # pylint: disable=W0613564 """565 Implements the match check for Python Unittests566 """567 return module.is_matching_klass(klass)568def find_python_unittests(path):569 found, _ = find_python_tests('unittest', 'TestCase',570 _determine_match_unittest,571 path)...

Full Screen

Full Screen

test_safeloader.py

Source:test_safeloader.py Github

copy

Full Screen

...445 self.module.add_imported_object(import_stm)446 self.assertEqual(self.module.imported_objects['baz'],447 os.path.join(self.path, 'foo', 'bar'))448 def test_is_not_avocado_test(self):449 self.assertFalse(self.module.is_matching_klass(ast.ClassDef()))450 def test_is_not_avocado_tests(self):451 for klass in self.module.iter_classes():452 self.assertFalse(self.module.is_matching_klass(klass))453class PythonModule(unittest.TestCase):454 """455 Has tests based on other Python source code files456 """457 def test_is_avocado_test(self):458 passtest_path = os.path.join(BASEDIR, 'examples', 'tests', 'passtest.py')459 passtest_module = safeloader.PythonModule(passtest_path)460 classes = [klass for klass in passtest_module.iter_classes()]461 # there's only one class and one *worthy* Test import in passtest.py462 self.assertEqual(len(classes), 1)463 self.assertEqual(len(passtest_module.klass_imports), 1)464 self.assertEqual(len(passtest_module.mod_imports), 0)465 self.assertTrue(passtest_module.is_matching_klass(classes[0]))466 def test_import_of_all_module_level(self):467 """468 Checks if all levels of a module import are taken into account469 This specific source file imports unittest.mock, and we want to470 make sure that unittest is accounted for.471 """472 path = os.path.join(BASEDIR, 'selftests', 'unit', 'test_loader.py')473 module = safeloader.PythonModule(path, 'unittest', 'TestCase')474 for _ in module.iter_classes():475 pass476 self.assertIn('unittest', module.mod_imports)477 def test_import_relative(self):478 """Tests if relative imports are tracked on the module object."""479 path = os.path.join(BASEDIR, 'selftests', 'functional', 'test_basic.py')...

Full Screen

Full Screen

test_safeloader_module.py

Source:test_safeloader_module.py Github

copy

Full Screen

...27 self.module.add_imported_symbol(import_stm)28 self.assertEqual(self.module.imported_symbols["baz"].module_path, "foo")29 self.assertEqual(self.module.imported_symbols["baz"].symbol, "bar")30 def test_is_not_avocado_test(self):31 self.assertFalse(self.module.is_matching_klass(ast.ClassDef()))32 def test_is_not_avocado_tests(self):33 for klass in self.module.iter_classes():34 self.assertFalse(self.module.is_matching_klass(klass))35class PythonModuleTest(unittest.TestCase):36 """37 Has tests based on other Python source code files38 """39 def test_is_avocado_test(self):40 passtest_path = os.path.join(BASEDIR, "examples", "tests", "passtest.py")41 passtest_module = PythonModule(passtest_path)42 classes = [klass for klass in passtest_module.iter_classes()]43 # there's only one class and one *worthy* Test import in passtest.py44 self.assertEqual(len(classes), 1)45 self.assertEqual(len(passtest_module.klass_imports), 1)46 self.assertEqual(len(passtest_module.mod_imports), 0)47 self.assertTrue(passtest_module.is_matching_klass(classes[0]))48 def test_import_of_all_module_level(self):49 """50 Checks if all levels of a module import are taken into account51 This specific source file imports unittest.mock, and we want to52 make sure that unittest is accounted for.53 """54 path = os.path.join(BASEDIR, "selftests", "unit", "test_loader.py")55 module = PythonModule(path, "unittest", "TestCase")56 for _ in module.iter_classes():57 pass58 self.assertIn("unittest", module.mod_imports)59 def test_import_relative(self):60 """Tests if relative imports are tracked on the module object."""61 path = os.path.join(BASEDIR, "selftests", "functional", "test_basic.py")...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run avocado automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful