diff options
| author | John L. Villalovos <john@sodarock.com> | 2021-11-07 14:33:39 -0800 |
|---|---|---|
| committer | John L. Villalovos <john@sodarock.com> | 2021-11-15 14:31:12 -0800 |
| commit | 46773a82565cef231dc3391c12f296ac307cb95c (patch) | |
| tree | 32cc9473ec28cc3d10be3baff28a74e8a17ac718 /tests | |
| parent | 94feb8a5534d43a464b717275846faa75783427e (diff) | |
| download | gitlab-46773a82565cef231dc3391c12f296ac307cb95c.tar.gz | |
chore: ensure get() methods have correct type-hintsjlvillal/mypy_ensure_type_hints
Fix classes which don't have correct 'get()' methods for classes
derived from GetMixin.
Add a unit test which verifies that classes have the correct return
type in their 'get()' method.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/meta/test_ensure_type_hints.py | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/tests/meta/test_ensure_type_hints.py b/tests/meta/test_ensure_type_hints.py new file mode 100644 index 0000000..f647b45 --- /dev/null +++ b/tests/meta/test_ensure_type_hints.py @@ -0,0 +1,85 @@ +""" +Ensure type-hints are setup correctly and detect if missing functions. + +Original notes by John L. Villalovos + +""" +import inspect +from typing import Tuple, Type + +import toml + +import gitlab.mixins +import gitlab.v4.objects + + +def pytest_generate_tests(metafunc): + """Find all of the classes in gitlab.v4.objects and pass them to our test + function""" + + # Ignore any modules that we are ignoring in our pyproject.toml + excluded_modules = set() + with open("pyproject.toml", "r") as in_file: + pyproject = toml.load(in_file) + overrides = pyproject.get("tool", {}).get("mypy", {}).get("overrides", []) + for override in overrides: + if not override.get("ignore_errors"): + continue + for module in override.get("module", []): + if module.startswith("gitlab.v4.objects"): + excluded_modules.add(module) + + class_info_list = [] + for module_name, module_value in inspect.getmembers(gitlab.v4.objects): + if not inspect.ismodule(module_value): + # We only care about the modules + continue + # Iterate through all the classes in our module + for class_name, class_value in inspect.getmembers(module_value): + if not inspect.isclass(class_value): + continue + + module_name = class_value.__module__ + # Ignore modules that mypy is ignoring + if module_name in excluded_modules: + continue + + # Ignore imported classes from gitlab.base + if module_name == "gitlab.base": + continue + + class_info_list.append((class_name, class_value)) + + metafunc.parametrize("class_info", class_info_list) + + +class TestTypeHints: + def test_check_get_function_type_hints(self, class_info: Tuple[str, Type]): + """Ensure classes derived from GetMixin have defined a 'get()' method with + correct type-hints. + """ + class_name, class_value = class_info + if not class_name.endswith("Manager"): + return + + mro = class_value.mro() + # The class needs to be derived from GetMixin or we ignore it + if gitlab.mixins.GetMixin not in mro: + return + + obj_cls = class_value._obj_cls + signature = inspect.signature(class_value.get) + filename = inspect.getfile(class_value) + + fail_message = ( + f"class definition for {class_name!r} in file {filename!r} " + f"must have defined a 'get' method with a return annotation of " + f"{obj_cls} but found {signature.return_annotation}\n" + f"Recommend adding the followinng method:\n" + f"def get(\n" + f" self, id: Union[str, int], lazy: bool = False, **kwargs: Any\n" + f" ) -> {obj_cls.__name__}:\n" + f" return cast({obj_cls.__name__}, super().get(id=id, lazy=lazy, " + f"**kwargs))\n" + ) + assert obj_cls == signature.return_annotation, fail_message |
