Check Salt loader modules for a defined `__virtualname__` attribute and `__virtual__` function. This is meant to replace: https://github.com/saltstack/salt/blob/27ae8260983b11fe6e32a18e777d550be9fe1dc2/tests/unit/test_virtualname.py
(
ctx: Context, files: list[pathlib.Path], enforce_virtualname: bool = False
)
| 28 | }, |
| 29 | ) |
| 30 | def check_virtual( |
| 31 | ctx: Context, files: list[pathlib.Path], enforce_virtualname: bool = False |
| 32 | ) -> None: |
| 33 | """ |
| 34 | Check Salt loader modules for a defined `__virtualname__` attribute and `__virtual__` function. |
| 35 | |
| 36 | This is meant to replace: |
| 37 | |
| 38 | https://github.com/saltstack/salt/blob/27ae8260983b11fe6e32a18e777d550be9fe1dc2/tests/unit/test_virtualname.py |
| 39 | """ |
| 40 | if not files: |
| 41 | _files = list(SALT_CODE_DIR.rglob("*.py")) |
| 42 | else: |
| 43 | _files = [fpath.resolve() for fpath in files if fpath.suffix == ".py"] |
| 44 | |
| 45 | errors = 0 |
| 46 | exitcode = 0 |
| 47 | for path in _files: |
| 48 | strpath = str(path) |
| 49 | if path.name == "__init__.py": |
| 50 | continue |
| 51 | for loader in SALT_INTERNAL_LOADERS_PATHS: |
| 52 | try: |
| 53 | path.relative_to(loader) |
| 54 | break |
| 55 | except ValueError: |
| 56 | # Path doesn't start with the loader path, carry on |
| 57 | continue |
| 58 | module = ast.parse(path.read_text(), filename=str(path)) |
| 59 | found_virtual_func = False |
| 60 | for funcdef in [ |
| 61 | node for node in module.body if isinstance(node, ast.FunctionDef) |
| 62 | ]: |
| 63 | if funcdef.name == "__virtual__": |
| 64 | found_virtual_func = True |
| 65 | break |
| 66 | if not found_virtual_func: |
| 67 | # If the module does not define a __virtual__() function, we don't require a __virtualname__ attribute |
| 68 | continue |
| 69 | |
| 70 | found_virtualname_attr = False |
| 71 | for node in module.body: |
| 72 | if isinstance(node, ast.Assign): |
| 73 | if not found_virtualname_attr: |
| 74 | for target in node.targets: |
| 75 | if not isinstance(target, ast.Name): |
| 76 | continue |
| 77 | if target.id == "__virtualname__": |
| 78 | found_virtualname_attr = True |
| 79 | attr_value = getattr( |
| 80 | node.value, "value", getattr(node.value, "s", None) |
| 81 | ) |
| 82 | if ( |
| 83 | not isinstance(attr_value, str) |
| 84 | or attr_value not in path.name |
| 85 | ): |
| 86 | errors += 1 |
| 87 | exitcode = 1 |