| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,5 @@ | |||
| 1 | 1 | [mypy] | |
| 2 | - files = gitlab/*.py | ||
| 2 | + files = gitlab/*.py,gitlab/v4/cli.py | ||
| 3 | 3 | ||
| 4 | 4 | # disallow_incomplete_defs: This flag reports an error whenever it encounters a | |
| 5 | 5 | # partly annotated function definition. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,8 +16,10 @@ | |||
| 16 | 16 | # You should have received a copy of the GNU Lesser General Public License | |
| 17 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 18 | 18 | ||
| 19 | + import argparse | ||
| 19 | 20 | import operator | |
| 20 | 21 | import sys | |
| 22 | + from typing import Any, Dict, List, Optional, Type, TYPE_CHECKING, Union | ||
| 21 | 23 | ||
| 22 | 24 | import gitlab | |
| 23 | 25 | import gitlab.base | |
@@ -26,18 +28,31 @@ | |||
| 26 | 28 | ||
| 27 | 29 | ||
| 28 | 30 | class GitlabCLI(object): | |
| 29 | - def __init__(self, gl, what, action, args): | ||
| 30 | - self.cls = cli.what_to_cls(what, namespace=gitlab.v4.objects) | ||
| 31 | + def __init__( | ||
| 32 | + self, gl: gitlab.Gitlab, what: str, action: str, args: Dict[str, str] | ||
| 33 | + ) -> None: | ||
| 34 | + self.cls: Type[gitlab.base.RESTObject] = cli.what_to_cls( | ||
| 35 | + what, namespace=gitlab.v4.objects | ||
| 36 | + ) | ||
| 31 | 37 | self.cls_name = self.cls.__name__ | |
| 32 | 38 | self.what = what.replace("-", "_") | |
| 33 | 39 | self.action = action.lower() | |
| 34 | 40 | self.gl = gl | |
| 35 | 41 | self.args = args | |
| 36 | - self.mgr_cls = getattr(gitlab.v4.objects, self.cls.__name__ + "Manager") | ||
| 42 | + self.mgr_cls: Union[ | ||
| 43 | + Type[gitlab.mixins.CreateMixin], | ||
| 44 | + Type[gitlab.mixins.DeleteMixin], | ||
| 45 | + Type[gitlab.mixins.GetMixin], | ||
| 46 | + Type[gitlab.mixins.GetWithoutIdMixin], | ||
| 47 | + Type[gitlab.mixins.ListMixin], | ||
| 48 | + Type[gitlab.mixins.UpdateMixin], | ||
| 49 | + ] = getattr(gitlab.v4.objects, self.cls.__name__ + "Manager") | ||
| 37 | 50 | # We could do something smart, like splitting the manager name to find | |
| 38 | 51 | # parents, build the chain of managers to get to the final object. | |
| 39 | 52 | # Instead we do something ugly and efficient: interpolate variables in | |
| 40 | 53 | # the class _path attribute, and replace the value with the result. | |
| 54 | + if TYPE_CHECKING: | ||
| 55 | + assert self.mgr_cls._path is not None | ||
| 41 | 56 | self.mgr_cls._path = self.mgr_cls._path % self.args | |
| 42 | 57 | self.mgr = self.mgr_cls(gl) | |
| 43 | 58 | ||
@@ -48,7 +63,7 @@ def __init__(self, gl, what, action, args): | |||
| 48 | 63 | obj.set_from_cli(self.args[attr_name]) | |
| 49 | 64 | self.args[attr_name] = obj.get() | |
| 50 | 65 | ||
| 51 | - def __call__(self): | ||
| 66 | + def __call__(self) -> Any: | ||
| 52 | 67 | # Check for a method that matches object + action | |
| 53 | 68 | method = "do_%s_%s" % (self.what, self.action) | |
| 54 | 69 | if hasattr(self, method): | |
@@ -62,7 +77,7 @@ def __call__(self): | |||
| 62 | 77 | # Finally try to find custom methods | |
| 63 | 78 | return self.do_custom() | |
| 64 | 79 | ||
| 65 | - def do_custom(self): | ||
| 80 | + def do_custom(self) -> Any: | ||
| 66 | 81 | in_obj = cli.custom_actions[self.cls_name][self.action][2] | |
| 67 | 82 | ||
| 68 | 83 | # Get the object (lazy), then act | |
@@ -72,14 +87,16 @@ def do_custom(self): | |||
| 72 | 87 | for k in self.mgr._from_parent_attrs: | |
| 73 | 88 | data[k] = self.args[k] | |
| 74 | 89 | if not issubclass(self.cls, gitlab.mixins.GetWithoutIdMixin): | |
| 90 | + if TYPE_CHECKING: | ||
| 91 | + assert isinstance(self.cls._id_attr, str) | ||
| 75 | 92 | data[self.cls._id_attr] = self.args.pop(self.cls._id_attr) | |
| 76 | - o = self.cls(self.mgr, data) | ||
| 93 | + obj = self.cls(self.mgr, data) | ||
| 77 | 94 | method_name = self.action.replace("-", "_") | |
| 78 | - return getattr(o, method_name)(**self.args) | ||
| 95 | + return getattr(obj, method_name)(**self.args) | ||
| 79 | 96 | else: | |
| 80 | 97 | return getattr(self.mgr, self.action)(**self.args) | |
| 81 | 98 | ||
| 82 | - def do_project_export_download(self): | ||
| 99 | + def do_project_export_download(self) -> None: | ||
| 83 | 100 | try: | |
| 84 | 101 | project = self.gl.projects.get(int(self.args["project_id"]), lazy=True) | |
| 85 | 102 | data = project.exports.get().download() | |
@@ -88,46 +105,75 @@ def do_project_export_download(self): | |||
| 88 | 105 | except Exception as e: | |
| 89 | 106 | cli.die("Impossible to download the export", e) | |
| 90 | 107 | ||
| 91 | - def do_create(self): | ||
| 108 | + def do_create(self) -> gitlab.base.RESTObject: | ||
| 109 | + if TYPE_CHECKING: | ||
| 110 | + assert isinstance(self.mgr, gitlab.mixins.CreateMixin) | ||
| 92 | 111 | try: | |
| 93 | - return self.mgr.create(self.args) | ||
| 112 | + result = self.mgr.create(self.args) | ||
| 94 | 113 | except Exception as e: | |
| 95 | 114 | cli.die("Impossible to create object", e) | |
| 115 | + return result | ||
| 96 | 116 | ||
| 97 | - def do_list(self): | ||
| 117 | + def do_list( | ||
| 118 | + self, | ||
| 119 | + ) -> Union[gitlab.base.RESTObjectList, List[gitlab.base.RESTObject]]: | ||
| 120 | + if TYPE_CHECKING: | ||
| 121 | + assert isinstance(self.mgr, gitlab.mixins.ListMixin) | ||
| 98 | 122 | try: | |
| 99 | - return self.mgr.list(**self.args) | ||
| 123 | + result = self.mgr.list(**self.args) | ||
| 100 | 124 | except Exception as e: | |
| 101 | 125 | cli.die("Impossible to list objects", e) | |
| 126 | + return result | ||
| 102 | 127 | ||
| 103 | - def do_get(self): | ||
| 104 | - id = None | ||
| 105 | - if not issubclass(self.mgr_cls, gitlab.mixins.GetWithoutIdMixin): | ||
| 106 | - id = self.args.pop(self.cls._id_attr) | ||
| 128 | + def do_get(self) -> Optional[gitlab.base.RESTObject]: | ||
| 129 | + if isinstance(self.mgr, gitlab.mixins.GetWithoutIdMixin): | ||
| 130 | + try: | ||
| 131 | + result = self.mgr.get(id=None, **self.args) | ||
| 132 | + except Exception as e: | ||
| 133 | + cli.die("Impossible to get object", e) | ||
| 134 | + return result | ||
| 107 | 135 | ||
| 136 | + if TYPE_CHECKING: | ||
| 137 | + assert isinstance(self.mgr, gitlab.mixins.GetMixin) | ||
| 138 | + assert isinstance(self.cls._id_attr, str) | ||
| 139 | + | ||
| 140 | + id = self.args.pop(self.cls._id_attr) | ||
| 108 | 141 | try: | |
| 109 | - return self.mgr.get(id, **self.args) | ||
| 142 | + result = self.mgr.get(id, lazy=False, **self.args) | ||
| 110 | 143 | except Exception as e: | |
| 111 | 144 | cli.die("Impossible to get object", e) | |
| 145 | + return result | ||
| 112 | 146 | ||
| 113 | - def do_delete(self): | ||
| 147 | + def do_delete(self) -> None: | ||
| 148 | + if TYPE_CHECKING: | ||
| 149 | + assert isinstance(self.mgr, gitlab.mixins.DeleteMixin) | ||
| 150 | + assert isinstance(self.cls._id_attr, str) | ||
| 114 | 151 | id = self.args.pop(self.cls._id_attr) | |
| 115 | 152 | try: | |
| 116 | 153 | self.mgr.delete(id, **self.args) | |
| 117 | 154 | except Exception as e: | |
| 118 | 155 | cli.die("Impossible to destroy object", e) | |
| 119 | 156 | ||
| 120 | - def do_update(self): | ||
| 121 | - id = None | ||
| 122 | - if not issubclass(self.mgr_cls, gitlab.mixins.GetWithoutIdMixin): | ||
| 157 | + def do_update(self) -> Dict[str, Any]: | ||
| 158 | + if TYPE_CHECKING: | ||
| 159 | + assert isinstance(self.mgr, gitlab.mixins.UpdateMixin) | ||
| 160 | + if issubclass(self.mgr_cls, gitlab.mixins.GetWithoutIdMixin): | ||
| 161 | + id = None | ||
| 162 | + else: | ||
| 163 | + if TYPE_CHECKING: | ||
| 164 | + assert isinstance(self.cls._id_attr, str) | ||
| 123 | 165 | id = self.args.pop(self.cls._id_attr) | |
| 166 | + | ||
| 124 | 167 | try: | |
| 125 | - return self.mgr.update(id, self.args) | ||
| 168 | + result = self.mgr.update(id, self.args) | ||
| 126 | 169 | except Exception as e: | |
| 127 | 170 | cli.die("Impossible to update object", e) | |
| 171 | + return result | ||
| 128 | 172 | ||
| 129 | 173 | ||
| 130 | - def _populate_sub_parser_by_class(cls, sub_parser): | ||
| 174 | + def _populate_sub_parser_by_class( | ||
| 175 | + cls: Type[gitlab.base.RESTObject], sub_parser: argparse._SubParsersAction | ||
| 176 | + ) -> None: | ||
| 131 | 177 | mgr_cls_name = cls.__name__ + "Manager" | |
| 132 | 178 | mgr_cls = getattr(gitlab.v4.objects, mgr_cls_name) | |
| 133 | 179 | ||
@@ -258,7 +304,7 @@ def _populate_sub_parser_by_class(cls, sub_parser): | |||
| 258 | 304 | ] | |
| 259 | 305 | ||
| 260 | 306 | ||
| 261 | - def extend_parser(parser): | ||
| 307 | + def extend_parser(parser: argparse.ArgumentParser) -> argparse.ArgumentParser: | ||
| 262 | 308 | subparsers = parser.add_subparsers( | |
| 263 | 309 | title="object", dest="what", help="Object to manipulate." | |
| 264 | 310 | ) | |
@@ -287,7 +333,9 @@ def extend_parser(parser): | |||
| 287 | 333 | return parser | |
| 288 | 334 | ||
| 289 | 335 | ||
| 290 | - def get_dict(obj, fields): | ||
| 336 | + def get_dict( | ||
| 337 | + obj: Union[str, gitlab.base.RESTObject], fields: List[str] | ||
| 338 | + ) -> Union[str, Dict[str, Any]]: | ||
| 291 | 339 | if isinstance(obj, str): | |
| 292 | 340 | return obj | |
| 293 | 341 | ||
@@ -297,19 +345,24 @@ def get_dict(obj, fields): | |||
| 297 | 345 | ||
| 298 | 346 | ||
| 299 | 347 | class JSONPrinter(object): | |
| 300 | - def display(self, d, **kwargs): | ||
| 348 | + def display(self, d: Union[str, Dict[str, Any]], **kwargs: Any) -> None: | ||
| 301 | 349 | import json # noqa | |
| 302 | 350 | ||
| 303 | 351 | print(json.dumps(d)) | |
| 304 | 352 | ||
| 305 | - def display_list(self, data, fields, **kwargs): | ||
| 353 | + def display_list( | ||
| 354 | + self, | ||
| 355 | + data: List[Union[str, gitlab.base.RESTObject]], | ||
| 356 | + fields: List[str], | ||
| 357 | + **kwargs: Any | ||
| 358 | + ) -> None: | ||
| 306 | 359 | import json # noqa | |
| 307 | 360 | ||
| 308 | 361 | print(json.dumps([get_dict(obj, fields) for obj in data])) | |
| 309 | 362 | ||
| 310 | 363 | ||
| 311 | 364 | class YAMLPrinter(object): | |
| 312 | - def display(self, d, **kwargs): | ||
| 365 | + def display(self, d: Union[str, Dict[str, Any]], **kwargs: Any) -> None: | ||
| 313 | 366 | try: | |
| 314 | 367 | import yaml # noqa | |
| 315 | 368 | ||
@@ -321,7 +374,12 @@ def display(self, d, **kwargs): | |||
| 321 | 374 | "to use the yaml output feature" | |
| 322 | 375 | ) | |
| 323 | 376 | ||
| 324 | - def display_list(self, data, fields, **kwargs): | ||
| 377 | + def display_list( | ||
| 378 | + self, | ||
| 379 | + data: List[Union[str, gitlab.base.RESTObject]], | ||
| 380 | + fields: List[str], | ||
| 381 | + **kwargs: Any | ||
| 382 | + ) -> None: | ||
| 325 | 383 | try: | |
| 326 | 384 | import yaml # noqa | |
| 327 | 385 | ||
@@ -339,12 +397,14 @@ def display_list(self, data, fields, **kwargs): | |||
| 339 | 397 | ||
| 340 | 398 | ||
| 341 | 399 | class LegacyPrinter(object): | |
| 342 | - def display(self, d, **kwargs): | ||
| 400 | + def display(self, d: Union[str, Dict[str, Any]], **kwargs: Any) -> None: | ||
| 343 | 401 | verbose = kwargs.get("verbose", False) | |
| 344 | 402 | padding = kwargs.get("padding", 0) | |
| 345 | - obj = kwargs.get("obj") | ||
| 403 | + obj: Optional[Union[Dict[str, Any], gitlab.base.RESTObject]] = kwargs.get("obj") | ||
| 404 | + if TYPE_CHECKING: | ||
| 405 | + assert obj is not None | ||
| 346 | 406 | ||
| 347 | - def display_dict(d, padding): | ||
| 407 | + def display_dict(d: Dict[str, Any], padding: int) -> None: | ||
| 348 | 408 | for k in sorted(d.keys()): | |
| 349 | 409 | v = d[k] | |
| 350 | 410 | if isinstance(v, dict): | |
@@ -369,6 +429,8 @@ def display_dict(d, padding): | |||
| 369 | 429 | display_dict(attrs, padding) | |
| 370 | 430 | ||
| 371 | 431 | else: | |
| 432 | + if TYPE_CHECKING: | ||
| 433 | + assert isinstance(obj, gitlab.base.RESTObject) | ||
| 372 | 434 | if obj._id_attr: | |
| 373 | 435 | id = getattr(obj, obj._id_attr) | |
| 374 | 436 | print("%s: %s" % (obj._id_attr.replace("_", "-"), id)) | |
@@ -383,7 +445,12 @@ def display_dict(d, padding): | |||
| 383 | 445 | line = line[:76] + "..." | |
| 384 | 446 | print(line) | |
| 385 | 447 | ||
| 386 | - def display_list(self, data, fields, **kwargs): | ||
| 448 | + def display_list( | ||
| 449 | + self, | ||
| 450 | + data: List[Union[str, gitlab.base.RESTObject]], | ||
| 451 | + fields: List[str], | ||
| 452 | + **kwargs: Any | ||
| 453 | + ) -> None: | ||
| 387 | 454 | verbose = kwargs.get("verbose", False) | |
| 388 | 455 | for obj in data: | |
| 389 | 456 | if isinstance(obj, gitlab.base.RESTObject): | |
@@ -393,14 +460,28 @@ def display_list(self, data, fields, **kwargs): | |||
| 393 | 460 | print("") | |
| 394 | 461 | ||
| 395 | 462 | ||
| 396 | - PRINTERS = {"json": JSONPrinter, "legacy": LegacyPrinter, "yaml": YAMLPrinter} | ||
| 397 | - | ||
| 398 | - | ||
| 399 | - def run(gl, what, action, args, verbose, output, fields): | ||
| 400 | - g_cli = GitlabCLI(gl, what, action, args) | ||
| 463 | + PRINTERS: Dict[ | ||
| 464 | + str, Union[Type[JSONPrinter], Type[LegacyPrinter], Type[YAMLPrinter]] | ||
| 465 | + ] = { | ||
| 466 | + "json": JSONPrinter, | ||
| 467 | + "legacy": LegacyPrinter, | ||
| 468 | + "yaml": YAMLPrinter, | ||
| 469 | + } | ||
| 470 | + | ||
| 471 | + | ||
| 472 | + def run( | ||
| 473 | + gl: gitlab.Gitlab, | ||
| 474 | + what: str, | ||
| 475 | + action: str, | ||
| 476 | + args: Dict[str, Any], | ||
| 477 | + verbose: bool, | ||
| 478 | + output: str, | ||
| 479 | + fields: List[str], | ||
| 480 | + ) -> None: | ||
| 481 | + g_cli = GitlabCLI(gl=gl, what=what, action=action, args=args) | ||
| 401 | 482 | data = g_cli() | |
| 402 | 483 | ||
| 403 | - printer = PRINTERS[output]() | ||
| 484 | + printer: Union[JSONPrinter, LegacyPrinter, YAMLPrinter] = PRINTERS[output]() | ||
| 404 | 485 | ||
| 405 | 486 | if isinstance(data, dict): | |
| 406 | 487 | printer.display(data, verbose=True, obj=data) | |
| Back | FazBrowse Home | New Git URL |
0 commit comments