| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -61,4 +61,4 @@ def update( | |||
| 61 | 61 | def get( | |
| 62 | 62 | self, id: Optional[Union[int, str]] = None, **kwargs: Any | |
| 63 | 63 | ) -> Optional[ApplicationAppearance]: | |
| 64 | - return cast(ApplicationAppearance, super().get(id=id, **kwargs)) | ||
| 64 | + return cast(Optional[ApplicationAppearance], super().get(id=id, **kwargs)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -27,7 +27,7 @@ class GroupExportManager(GetWithoutIdMixin, CreateMixin, RESTManager): | |||
| 27 | 27 | def get( | |
| 28 | 28 | self, id: Optional[Union[int, str]] = None, **kwargs: Any | |
| 29 | 29 | ) -> Optional[GroupExport]: | |
| 30 | - return cast(GroupExport, super().get(id=id, **kwargs)) | ||
| 30 | + return cast(Optional[GroupExport], super().get(id=id, **kwargs)) | ||
| 31 | 31 | ||
| 32 | 32 | ||
| 33 | 33 | class GroupImport(RESTObject): | |
@@ -42,7 +42,7 @@ class GroupImportManager(GetWithoutIdMixin, RESTManager): | |||
| 42 | 42 | def get( | |
| 43 | 43 | self, id: Optional[Union[int, str]] = None, **kwargs: Any | |
| 44 | 44 | ) -> Optional[GroupImport]: | |
| 45 | - return cast(GroupImport, super().get(id=id, **kwargs)) | ||
| 45 | + return cast(Optional[GroupImport], super().get(id=id, **kwargs)) | ||
| 46 | 46 | ||
| 47 | 47 | ||
| 48 | 48 | class ProjectExport(DownloadMixin, RefreshMixin, RESTObject): | |
@@ -58,7 +58,7 @@ class ProjectExportManager(GetWithoutIdMixin, CreateMixin, RESTManager): | |||
| 58 | 58 | def get( | |
| 59 | 59 | self, id: Optional[Union[int, str]] = None, **kwargs: Any | |
| 60 | 60 | ) -> Optional[ProjectExport]: | |
| 61 | - return cast(ProjectExport, super().get(id=id, **kwargs)) | ||
| 61 | + return cast(Optional[ProjectExport], super().get(id=id, **kwargs)) | ||
| 62 | 62 | ||
| 63 | 63 | ||
| 64 | 64 | class ProjectImport(RefreshMixin, RESTObject): | |
@@ -73,4 +73,4 @@ class ProjectImportManager(GetWithoutIdMixin, RESTManager): | |||
| 73 | 73 | def get( | |
| 74 | 74 | self, id: Optional[Union[int, str]] = None, **kwargs: Any | |
| 75 | 75 | ) -> Optional[ProjectImport]: | |
| 76 | - return cast(ProjectImport, super().get(id=id, **kwargs)) | ||
| 76 | + return cast(Optional[ProjectImport], super().get(id=id, **kwargs)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,4 @@ | |||
| 1 | - from typing import Any, Dict, List, Optional, TYPE_CHECKING | ||
| 1 | + from typing import Any, cast, Dict, List, Optional, TYPE_CHECKING, Union | ||
| 2 | 2 | ||
| 3 | 3 | from gitlab import exceptions as exc | |
| 4 | 4 | from gitlab.base import RequiredOptional, RESTManager, RESTObject | |
@@ -45,6 +45,11 @@ class ProjectApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTManager): | |||
| 45 | 45 | ) | |
| 46 | 46 | _update_uses_post = True | |
| 47 | 47 | ||
| 48 | + def get( | ||
| 49 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 50 | + ) -> Optional[ProjectApproval]: | ||
| 51 | + return cast(Optional[ProjectApproval], super().get(id=id, **kwargs)) | ||
| 52 | + | ||
| 48 | 53 | @exc.on_http_error(exc.GitlabUpdateError) | |
| 49 | 54 | def set_approvers( | |
| 50 | 55 | self, | |
@@ -105,6 +110,11 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan | |||
| 105 | 110 | _update_attrs = RequiredOptional(required=("approvals_required",)) | |
| 106 | 111 | _update_uses_post = True | |
| 107 | 112 | ||
| 113 | + def get( | ||
| 114 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 115 | + ) -> Optional[ProjectMergeRequestApproval]: | ||
| 116 | + return cast(Optional[ProjectMergeRequestApproval], super().get(id=id, **kwargs)) | ||
| 117 | + | ||
| 108 | 118 | @exc.on_http_error(exc.GitlabUpdateError) | |
| 109 | 119 | def set_approvers( | |
| 110 | 120 | self, | |
@@ -241,3 +251,10 @@ class ProjectMergeRequestApprovalStateManager(GetWithoutIdMixin, RESTManager): | |||
| 241 | 251 | _path = "/projects/{project_id}/merge_requests/{mr_iid}/approval_state" | |
| 242 | 252 | _obj_cls = ProjectMergeRequestApprovalState | |
| 243 | 253 | _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} | |
| 254 | + | ||
| 255 | + def get( | ||
| 256 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 257 | + ) -> Optional[ProjectMergeRequestApprovalState]: | ||
| 258 | + return cast( | ||
| 259 | + Optional[ProjectMergeRequestApprovalState], super().get(id=id, **kwargs) | ||
| 260 | + ) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,3 +1,5 @@ | |||
| 1 | + from typing import Any, cast, Optional, Union | ||
| 2 | + | ||
| 1 | 3 | from gitlab.base import RequiredOptional, RESTManager, RESTObject | |
| 2 | 4 | from gitlab.mixins import GetWithoutIdMixin, SaveMixin, UpdateMixin | |
| 3 | 5 | ||
@@ -36,6 +38,11 @@ class NotificationSettingsManager(GetWithoutIdMixin, UpdateMixin, RESTManager): | |||
| 36 | 38 | ), | |
| 37 | 39 | ) | |
| 38 | 40 | ||
| 41 | + def get( | ||
| 42 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 43 | + ) -> Optional[NotificationSettings]: | ||
| 44 | + return cast(Optional[NotificationSettings], super().get(id=id, **kwargs)) | ||
| 45 | + | ||
| 39 | 46 | ||
| 40 | 47 | class GroupNotificationSettings(NotificationSettings): | |
| 41 | 48 | pass | |
@@ -46,6 +53,11 @@ class GroupNotificationSettingsManager(NotificationSettingsManager): | |||
| 46 | 53 | _obj_cls = GroupNotificationSettings | |
| 47 | 54 | _from_parent_attrs = {"group_id": "id"} | |
| 48 | 55 | ||
| 56 | + def get( | ||
| 57 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 58 | + ) -> Optional[GroupNotificationSettings]: | ||
| 59 | + return cast(Optional[GroupNotificationSettings], super().get(id=id, **kwargs)) | ||
| 60 | + | ||
| 49 | 61 | ||
| 50 | 62 | class ProjectNotificationSettings(NotificationSettings): | |
| 51 | 63 | pass | |
@@ -55,3 +67,8 @@ class ProjectNotificationSettingsManager(NotificationSettingsManager): | |||
| 55 | 67 | _path = "/projects/{project_id}/notification_settings" | |
| 56 | 68 | _obj_cls = ProjectNotificationSettings | |
| 57 | 69 | _from_parent_attrs = {"project_id": "id"} | |
| 70 | + | ||
| 71 | + def get( | ||
| 72 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 73 | + ) -> Optional[ProjectNotificationSettings]: | ||
| 74 | + return cast(Optional[ProjectNotificationSettings], super().get(id=id, **kwargs)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -246,3 +246,8 @@ class ProjectPipelineTestReportManager(GetWithoutIdMixin, RESTManager): | |||
| 246 | 246 | _path = "/projects/{project_id}/pipelines/{pipeline_id}/test_report" | |
| 247 | 247 | _obj_cls = ProjectPipelineTestReport | |
| 248 | 248 | _from_parent_attrs = {"project_id": "project_id", "pipeline_id": "id"} | |
| 249 | + | ||
| 250 | + def get( | ||
| 251 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 252 | + ) -> Optional[ProjectPipelineTestReport]: | ||
| 253 | + return cast(Optional[ProjectPipelineTestReport], super().get(id=id, **kwargs)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -54,4 +54,4 @@ class ProjectPushRulesManager( | |||
| 54 | 54 | def get( | |
| 55 | 55 | self, id: Optional[Union[int, str]] = None, **kwargs: Any | |
| 56 | 56 | ) -> Optional[ProjectPushRules]: | |
| 57 | - return cast(ProjectPushRules, super().get(id=id, **kwargs)) | ||
| 57 | + return cast(Optional[ProjectPushRules], super().get(id=id, **kwargs)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -118,4 +118,4 @@ def update( | |||
| 118 | 118 | def get( | |
| 119 | 119 | self, id: Optional[Union[int, str]] = None, **kwargs: Any | |
| 120 | 120 | ) -> Optional[ApplicationSettings]: | |
| 121 | - return cast(ApplicationSettings, super().get(id=id, **kwargs)) | ||
| 121 | + return cast(Optional[ApplicationSettings], super().get(id=id, **kwargs)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,3 +1,5 @@ | |||
| 1 | + from typing import Any, cast, Optional, Union | ||
| 2 | + | ||
| 1 | 3 | from gitlab.base import RESTManager, RESTObject | |
| 2 | 4 | from gitlab.mixins import GetWithoutIdMixin, RefreshMixin | |
| 3 | 5 | ||
@@ -22,6 +24,11 @@ class ProjectAdditionalStatisticsManager(GetWithoutIdMixin, RESTManager): | |||
| 22 | 24 | _obj_cls = ProjectAdditionalStatistics | |
| 23 | 25 | _from_parent_attrs = {"project_id": "id"} | |
| 24 | 26 | ||
| 27 | + def get( | ||
| 28 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 29 | + ) -> Optional[ProjectAdditionalStatistics]: | ||
| 30 | + return cast(Optional[ProjectAdditionalStatistics], super().get(id=id, **kwargs)) | ||
| 31 | + | ||
| 25 | 32 | ||
| 26 | 33 | class IssuesStatistics(RefreshMixin, RESTObject): | |
| 27 | 34 | _id_attr = None | |
@@ -31,6 +38,11 @@ class IssuesStatisticsManager(GetWithoutIdMixin, RESTManager): | |||
| 31 | 38 | _path = "/issues_statistics" | |
| 32 | 39 | _obj_cls = IssuesStatistics | |
| 33 | 40 | ||
| 41 | + def get( | ||
| 42 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 43 | + ) -> Optional[IssuesStatistics]: | ||
| 44 | + return cast(Optional[IssuesStatistics], super().get(id=id, **kwargs)) | ||
| 45 | + | ||
| 34 | 46 | ||
| 35 | 47 | class GroupIssuesStatistics(RefreshMixin, RESTObject): | |
| 36 | 48 | _id_attr = None | |
@@ -41,6 +53,11 @@ class GroupIssuesStatisticsManager(GetWithoutIdMixin, RESTManager): | |||
| 41 | 53 | _obj_cls = GroupIssuesStatistics | |
| 42 | 54 | _from_parent_attrs = {"group_id": "id"} | |
| 43 | 55 | ||
| 56 | + def get( | ||
| 57 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 58 | + ) -> Optional[GroupIssuesStatistics]: | ||
| 59 | + return cast(Optional[GroupIssuesStatistics], super().get(id=id, **kwargs)) | ||
| 60 | + | ||
| 44 | 61 | ||
| 45 | 62 | class ProjectIssuesStatistics(RefreshMixin, RESTObject): | |
| 46 | 63 | _id_attr = None | |
@@ -50,3 +67,8 @@ class ProjectIssuesStatisticsManager(GetWithoutIdMixin, RESTManager): | |||
| 50 | 67 | _path = "/projects/{project_id}/issues_statistics" | |
| 51 | 68 | _obj_cls = ProjectIssuesStatistics | |
| 52 | 69 | _from_parent_attrs = {"project_id": "id"} | |
| 70 | + | ||
| 71 | + def get( | ||
| 72 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 73 | + ) -> Optional[ProjectIssuesStatistics]: | ||
| 74 | + return cast(Optional[ProjectIssuesStatistics], super().get(id=id, **kwargs)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,7 +3,7 @@ | |||
| 3 | 3 | https://docs.gitlab.com/ee/api/users.html | |
| 4 | 4 | https://docs.gitlab.com/ee/api/projects.html#list-projects-starred-by-a-user | |
| 5 | 5 | """ | |
| 6 | - from typing import Any, cast, Dict, List, Union | ||
| 6 | + from typing import Any, cast, Dict, List, Optional, Union | ||
| 7 | 7 | ||
| 8 | 8 | import requests | |
| 9 | 9 | ||
@@ -120,6 +120,11 @@ class CurrentUserStatusManager(GetWithoutIdMixin, UpdateMixin, RESTManager): | |||
| 120 | 120 | _obj_cls = CurrentUserStatus | |
| 121 | 121 | _update_attrs = RequiredOptional(optional=("emoji", "message")) | |
| 122 | 122 | ||
| 123 | + def get( | ||
| 124 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 125 | + ) -> Optional[CurrentUserStatus]: | ||
| 126 | + return cast(Optional[CurrentUserStatus], super().get(id=id, **kwargs)) | ||
| 127 | + | ||
| 123 | 128 | ||
| 124 | 129 | class CurrentUser(RESTObject): | |
| 125 | 130 | _id_attr = None | |
@@ -135,6 +140,11 @@ class CurrentUserManager(GetWithoutIdMixin, RESTManager): | |||
| 135 | 140 | _path = "/user" | |
| 136 | 141 | _obj_cls = CurrentUser | |
| 137 | 142 | ||
| 143 | + def get( | ||
| 144 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 145 | + ) -> Optional[CurrentUser]: | ||
| 146 | + return cast(Optional[CurrentUser], super().get(id=id, **kwargs)) | ||
| 147 | + | ||
| 138 | 148 | ||
| 139 | 149 | class User(SaveMixin, ObjectDeleteMixin, RESTObject): | |
| 140 | 150 | _short_print_attr = "username" | |
@@ -390,6 +400,11 @@ class UserStatusManager(GetWithoutIdMixin, RESTManager): | |||
| 390 | 400 | _obj_cls = UserStatus | |
| 391 | 401 | _from_parent_attrs = {"user_id": "id"} | |
| 392 | 402 | ||
| 403 | + def get( | ||
| 404 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 405 | + ) -> Optional[UserStatus]: | ||
| 406 | + return cast(Optional[UserStatus], super().get(id=id, **kwargs)) | ||
| 407 | + | ||
| 393 | 408 | ||
| 394 | 409 | class UserActivitiesManager(ListMixin, RESTManager): | |
| 395 | 410 | _path = "/user/activities" | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,15 +4,34 @@ | |||
| 4 | 4 | Original notes by John L. Villalovos | |
| 5 | 5 | ||
| 6 | 6 | """ | |
| 7 | + import dataclasses | ||
| 8 | + import functools | ||
| 7 | 9 | import inspect | |
| 8 | - from typing import Tuple, Type | ||
| 10 | + from typing import Optional, Type | ||
| 9 | 11 | ||
| 10 | 12 | import _pytest | |
| 11 | 13 | ||
| 12 | 14 | import gitlab.mixins | |
| 13 | 15 | import gitlab.v4.objects | |
| 14 | 16 | ||
| 15 | 17 | ||
| 18 | + @functools.total_ordering | ||
| 19 | + @dataclasses.dataclass(frozen=True) | ||
| 20 | + class ClassInfo: | ||
| 21 | + name: str | ||
| 22 | + type: Type | ||
| 23 | + | ||
| 24 | + def __lt__(self, other: object) -> bool: | ||
| 25 | + if not isinstance(other, ClassInfo): | ||
| 26 | + return NotImplemented | ||
| 27 | + return (self.type.__module__, self.name) < (other.type.__module__, other.name) | ||
| 28 | + | ||
| 29 | + def __eq__(self, other: object) -> bool: | ||
| 30 | + if not isinstance(other, ClassInfo): | ||
| 31 | + return NotImplemented | ||
| 32 | + return (self.type.__module__, self.name) == (other.type.__module__, other.name) | ||
| 33 | + | ||
| 34 | + | ||
| 16 | 35 | def pytest_generate_tests(metafunc: _pytest.python.Metafunc) -> None: | |
| 17 | 36 | """Find all of the classes in gitlab.v4.objects and pass them to our test | |
| 18 | 37 | function""" | |
@@ -35,38 +54,84 @@ def pytest_generate_tests(metafunc: _pytest.python.Metafunc) -> None: | |||
| 35 | 54 | if not class_name.endswith("Manager"): | |
| 36 | 55 | continue | |
| 37 | 56 | ||
| 38 | - class_info_set.add((class_name, class_value)) | ||
| 57 | + class_info_set.add(ClassInfo(name=class_name, type=class_value)) | ||
| 58 | + | ||
| 59 | + metafunc.parametrize("class_info", sorted(class_info_set)) | ||
| 39 | 60 | ||
| 40 | - metafunc.parametrize("class_info", class_info_set) | ||
| 61 | + | ||
| 62 | + GET_ID_METHOD_TEMPLATE = """ | ||
| 63 | + def get( | ||
| 64 | + self, id: Union[str, int], lazy: bool = False, **kwargs: Any | ||
| 65 | + ) -> {obj_cls.__name__}: | ||
| 66 | + return cast({obj_cls.__name__}, super().get(id=id, lazy=lazy, **kwargs)) | ||
| 67 | + | ||
| 68 | + You may also need to add the following imports: | ||
| 69 | + from typing import Any, cast, Union" | ||
| 70 | + """ | ||
| 71 | + | ||
| 72 | + GET_WITHOUT_ID_METHOD_TEMPLATE = """ | ||
| 73 | + def get( | ||
| 74 | + self, id: Optional[Union[int, str]] = None, **kwargs: Any | ||
| 75 | + ) -> Optional[{obj_cls.__name__}]: | ||
| 76 | + return cast(Optional[{obj_cls.__name__}], super().get(id=id, **kwargs)) | ||
| 77 | + | ||
| 78 | + You may also need to add the following imports: | ||
| 79 | + from typing import Any, cast, Optional, Union" | ||
| 80 | + """ | ||
| 41 | 81 | ||
| 42 | 82 | ||
| 43 | 83 | class TestTypeHints: | |
| 44 | - def test_check_get_function_type_hints(self, class_info: Tuple[str, Type]) -> None: | ||
| 84 | + def test_check_get_function_type_hints(self, class_info: ClassInfo) -> None: | ||
| 45 | 85 | """Ensure classes derived from GetMixin have defined a 'get()' method with | |
| 46 | 86 | correct type-hints. | |
| 47 | 87 | """ | |
| 48 | - class_name, class_value = class_info | ||
| 49 | - if not class_name.endswith("Manager"): | ||
| 50 | - return | ||
| 88 | + self.get_check_helper( | ||
| 89 | + base_type=gitlab.mixins.GetMixin, | ||
| 90 | + class_info=class_info, | ||
| 91 | + method_template=GET_ID_METHOD_TEMPLATE, | ||
| 92 | + optional_return=False, | ||
| 93 | + ) | ||
| 51 | 94 | ||
| 52 | - mro = class_value.mro() | ||
| 95 | + def test_check_get_without_id_function_type_hints( | ||
| 96 | + self, class_info: ClassInfo | ||
| 97 | + ) -> None: | ||
| 98 | + """Ensure classes derived from GetMixin have defined a 'get()' method with | ||
| 99 | + correct type-hints. | ||
| 100 | + """ | ||
| 101 | + self.get_check_helper( | ||
| 102 | + base_type=gitlab.mixins.GetWithoutIdMixin, | ||
| 103 | + class_info=class_info, | ||
| 104 | + method_template=GET_WITHOUT_ID_METHOD_TEMPLATE, | ||
| 105 | + optional_return=True, | ||
| 106 | + ) | ||
| 107 | + | ||
| 108 | + def get_check_helper( | ||
| 109 | + self, | ||
| 110 | + *, | ||
| 111 | + base_type: Type, | ||
| 112 | + class_info: ClassInfo, | ||
| 113 | + method_template: str, | ||
| 114 | + optional_return: bool, | ||
| 115 | + ) -> None: | ||
| 116 | + if not class_info.name.endswith("Manager"): | ||
| 117 | + return | ||
| 118 | + mro = class_info.type.mro() | ||
| 53 | 119 | # The class needs to be derived from GetMixin or we ignore it | |
| 54 | - if gitlab.mixins.GetMixin not in mro: | ||
| 120 | + if base_type not in mro: | ||
| 55 | 121 | return | |
| 56 | 122 | ||
| 57 | - obj_cls = class_value._obj_cls | ||
| 58 | - signature = inspect.signature(class_value.get) | ||
| 59 | - filename = inspect.getfile(class_value) | ||
| 123 | + obj_cls = class_info.type._obj_cls | ||
| 124 | + signature = inspect.signature(class_info.type.get) | ||
| 125 | + filename = inspect.getfile(class_info.type) | ||
| 60 | 126 | ||
| 61 | 127 | fail_message = ( | |
| 62 | - f"class definition for {class_name!r} in file {filename!r} " | ||
| 128 | + f"class definition for {class_info.name!r} in file {filename!r} " | ||
| 63 | 129 | f"must have defined a 'get' method with a return annotation of " | |
| 64 | 130 | f"{obj_cls} but found {signature.return_annotation}\n" | |
| 65 | 131 | f"Recommend adding the followinng method:\n" | |
| 66 | - f"def get(\n" | ||
| 67 | - f" self, id: Union[str, int], lazy: bool = False, **kwargs: Any\n" | ||
| 68 | - f" ) -> {obj_cls.__name__}:\n" | ||
| 69 | - f" return cast({obj_cls.__name__}, super().get(id=id, lazy=lazy, " | ||
| 70 | - f"**kwargs))\n" | ||
| 71 | 132 | ) | |
| 72 | - assert obj_cls == signature.return_annotation, fail_message | ||
| 133 | + fail_message += method_template.format(obj_cls=obj_cls) | ||
| 134 | + check_type = obj_cls | ||
| 135 | + if optional_return: | ||
| 136 | + check_type = Optional[obj_cls] | ||
| 137 | + assert check_type == signature.return_annotation, fail_message | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments