diff options
| author | Nejc Habjan <hab.nejc@gmail.com> | 2021-12-11 12:07:16 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-12-11 12:07:16 +0100 |
| commit | ac5defa0c09822cf2208e66218a37d3ce00ff35b (patch) | |
| tree | 27993a4ff20957f845033b1aef394f0e036e330e /tests | |
| parent | 2f37ccb5cd8c487662e86aa077f1deabb27fbc9e (diff) | |
| parent | d27c50ab9d55dd715a7bee5b0c61317f8565c8bf (diff) | |
| download | gitlab-ac5defa0c09822cf2208e66218a37d3ce00ff35b.tar.gz | |
Merge pull request #1710 from python-gitlab/jlvillal/get_without_id
chore: add get() methods for GetWithoutIdMixin based classes
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/meta/test_ensure_type_hints.py | 103 |
1 files changed, 84 insertions, 19 deletions
diff --git a/tests/meta/test_ensure_type_hints.py b/tests/meta/test_ensure_type_hints.py index a770afb..2449324 100644 --- a/tests/meta/test_ensure_type_hints.py +++ b/tests/meta/test_ensure_type_hints.py @@ -4,8 +4,10 @@ Ensure type-hints are setup correctly and detect if missing functions. Original notes by John L. Villalovos """ +import dataclasses +import functools import inspect -from typing import Tuple, Type +from typing import Optional, Type import _pytest @@ -13,6 +15,23 @@ import gitlab.mixins import gitlab.v4.objects +@functools.total_ordering +@dataclasses.dataclass(frozen=True) +class ClassInfo: + name: str + type: Type + + def __lt__(self, other: object) -> bool: + if not isinstance(other, ClassInfo): + return NotImplemented + return (self.type.__module__, self.name) < (other.type.__module__, other.name) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ClassInfo): + return NotImplemented + return (self.type.__module__, self.name) == (other.type.__module__, other.name) + + def pytest_generate_tests(metafunc: _pytest.python.Metafunc) -> None: """Find all of the classes in gitlab.v4.objects and pass them to our test function""" @@ -35,38 +54,84 @@ def pytest_generate_tests(metafunc: _pytest.python.Metafunc) -> None: if not class_name.endswith("Manager"): continue - class_info_set.add((class_name, class_value)) + class_info_set.add(ClassInfo(name=class_name, type=class_value)) + + metafunc.parametrize("class_info", sorted(class_info_set)) - metafunc.parametrize("class_info", class_info_set) + +GET_ID_METHOD_TEMPLATE = """ +def get( + self, id: Union[str, int], lazy: bool = False, **kwargs: Any +) -> {obj_cls.__name__}: + return cast({obj_cls.__name__}, super().get(id=id, lazy=lazy, **kwargs)) + +You may also need to add the following imports: +from typing import Any, cast, Union" +""" + +GET_WITHOUT_ID_METHOD_TEMPLATE = """ +def get( + self, id: Optional[Union[int, str]] = None, **kwargs: Any +) -> Optional[{obj_cls.__name__}]: + return cast(Optional[{obj_cls.__name__}], super().get(id=id, **kwargs)) + +You may also need to add the following imports: +from typing import Any, cast, Optional, Union" +""" class TestTypeHints: - def test_check_get_function_type_hints(self, class_info: Tuple[str, Type]) -> None: + def test_check_get_function_type_hints(self, class_info: ClassInfo) -> None: """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 + self.get_check_helper( + base_type=gitlab.mixins.GetMixin, + class_info=class_info, + method_template=GET_ID_METHOD_TEMPLATE, + optional_return=False, + ) - mro = class_value.mro() + def test_check_get_without_id_function_type_hints( + self, class_info: ClassInfo + ) -> None: + """Ensure classes derived from GetMixin have defined a 'get()' method with + correct type-hints. + """ + self.get_check_helper( + base_type=gitlab.mixins.GetWithoutIdMixin, + class_info=class_info, + method_template=GET_WITHOUT_ID_METHOD_TEMPLATE, + optional_return=True, + ) + + def get_check_helper( + self, + *, + base_type: Type, + class_info: ClassInfo, + method_template: str, + optional_return: bool, + ) -> None: + if not class_info.name.endswith("Manager"): + return + mro = class_info.type.mro() # The class needs to be derived from GetMixin or we ignore it - if gitlab.mixins.GetMixin not in mro: + if base_type not in mro: return - obj_cls = class_value._obj_cls - signature = inspect.signature(class_value.get) - filename = inspect.getfile(class_value) + obj_cls = class_info.type._obj_cls + signature = inspect.signature(class_info.type.get) + filename = inspect.getfile(class_info.type) fail_message = ( - f"class definition for {class_name!r} in file {filename!r} " + f"class definition for {class_info.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 + fail_message += method_template.format(obj_cls=obj_cls) + check_type = obj_cls + if optional_return: + check_type = Optional[obj_cls] + assert check_type == signature.return_annotation, fail_message |
