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
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 )
0 commit comments