1616# You should have received a copy of the GNU Lesser General Public License
1717# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
19+ import argparse
1920import operator
2021import sys
22+ from typing import Any , Dict , List , Optional , Type , TYPE_CHECKING , Union
2123
2224import gitlab
2325import gitlab .base
2628
2729
2830class 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+ )
3137 self .cls_name = self .cls .__name__
3238 self .what = what .replace ("-" , "_" )
3339 self .action = action .lower ()
3440 self .gl = gl
3541 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" )
3750 # We could do something smart, like splitting the manager name to find
3851 # parents, build the chain of managers to get to the final object.
3952 # Instead we do something ugly and efficient: interpolate variables in
4053 # the class _path attribute, and replace the value with the result.
54+ if TYPE_CHECKING :
55+ assert self .mgr_cls ._path is not None
4156 self .mgr_cls ._path = self .mgr_cls ._path % self .args
4257 self .mgr = self .mgr_cls (gl )
4358
@@ -48,7 +63,7 @@ def __init__(self, gl, what, action, args):
4863 obj .set_from_cli (self .args [attr_name ])
4964 self .args [attr_name ] = obj .get ()
5065
51- def __call__ (self ):
66+ def __call__ (self ) -> Any :
5267 # Check for a method that matches object + action
5368 method = "do_%s_%s" % (self .what , self .action )
5469 if hasattr (self , method ):
@@ -62,7 +77,7 @@ def __call__(self):
6277 # Finally try to find custom methods
6378 return self .do_custom ()
6479
65- def do_custom (self ):
80+ def do_custom (self ) -> Any :
6681 in_obj = cli .custom_actions [self .cls_name ][self .action ][2 ]
6782
6883 # Get the object (lazy), then act
@@ -72,14 +87,16 @@ def do_custom(self):
7287 for k in self .mgr ._from_parent_attrs :
7388 data [k ] = self .args [k ]
7489 if not issubclass (self .cls , gitlab .mixins .GetWithoutIdMixin ):
90+ if TYPE_CHECKING :
91+ assert isinstance (self .cls ._id_attr , str )
7592 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 )
7794 method_name = self .action .replace ("-" , "_" )
78- return getattr (o , method_name )(** self .args )
95+ return getattr (obj , method_name )(** self .args )
7996 else :
8097 return getattr (self .mgr , self .action )(** self .args )
8198
82- def do_project_export_download (self ):
99+ def do_project_export_download (self ) -> None :
83100 try :
84101 project = self .gl .projects .get (int (self .args ["project_id" ]), lazy = True )
85102 data = project .exports .get ().download ()
@@ -88,46 +105,75 @@ def do_project_export_download(self):
88105 except Exception as e :
89106 cli .die ("Impossible to download the export" , e )
90107
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 )
92111 try :
93- return self .mgr .create (self .args )
112+ result = self .mgr .create (self .args )
94113 except Exception as e :
95114 cli .die ("Impossible to create object" , e )
115+ return result
96116
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 )
98122 try :
99- return self .mgr .list (** self .args )
123+ result = self .mgr .list (** self .args )
100124 except Exception as e :
101125 cli .die ("Impossible to list objects" , e )
126+ return result
102127
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
107135
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 )
108141 try :
109- return self .mgr .get (id , ** self .args )
142+ result = self .mgr .get (id , lazy = False , ** self .args )
110143 except Exception as e :
111144 cli .die ("Impossible to get object" , e )
145+ return result
112146
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 )
114151 id = self .args .pop (self .cls ._id_attr )
115152 try :
116153 self .mgr .delete (id , ** self .args )
117154 except Exception as e :
118155 cli .die ("Impossible to destroy object" , e )
119156
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 )
123165 id = self .args .pop (self .cls ._id_attr )
166+
124167 try :
125- return self .mgr .update (id , self .args )
168+ result = self .mgr .update (id , self .args )
126169 except Exception as e :
127170 cli .die ("Impossible to update object" , e )
171+ return result
128172
129173
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 :
131177 mgr_cls_name = cls .__name__ + "Manager"
132178 mgr_cls = getattr (gitlab .v4 .objects , mgr_cls_name )
133179
@@ -258,7 +304,7 @@ def _populate_sub_parser_by_class(cls, sub_parser):
258304 ]
259305
260306
261- def extend_parser (parser ) :
307+ def extend_parser (parser : argparse . ArgumentParser ) -> argparse . ArgumentParser :
262308 subparsers = parser .add_subparsers (
263309 title = "object" , dest = "what" , help = "Object to manipulate."
264310 )
@@ -287,7 +333,9 @@ def extend_parser(parser):
287333 return parser
288334
289335
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 ]]:
291339 if isinstance (obj , str ):
292340 return obj
293341
@@ -297,19 +345,24 @@ def get_dict(obj, fields):
297345
298346
299347class JSONPrinter (object ):
300- def display (self , d , ** kwargs ) :
348+ def display (self , d : Union [ str , Dict [ str , Any ]], ** kwargs : Any ) -> None :
301349 import json # noqa
302350
303351 print (json .dumps (d ))
304352
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 :
306359 import json # noqa
307360
308361 print (json .dumps ([get_dict (obj , fields ) for obj in data ]))
309362
310363
311364class YAMLPrinter (object ):
312- def display (self , d , ** kwargs ) :
365+ def display (self , d : Union [ str , Dict [ str , Any ]], ** kwargs : Any ) -> None :
313366 try :
314367 import yaml # noqa
315368
@@ -321,7 +374,12 @@ def display(self, d, **kwargs):
321374 "to use the yaml output feature"
322375 )
323376
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 :
325383 try :
326384 import yaml # noqa
327385
@@ -339,12 +397,14 @@ def display_list(self, data, fields, **kwargs):
339397
340398
341399class LegacyPrinter (object ):
342- def display (self , d , ** kwargs ) :
400+ def display (self , d : Union [ str , Dict [ str , Any ]], ** kwargs : Any ) -> None :
343401 verbose = kwargs .get ("verbose" , False )
344402 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
346406
347- def display_dict (d , padding ) :
407+ def display_dict (d : Dict [ str , Any ], padding : int ) -> None :
348408 for k in sorted (d .keys ()):
349409 v = d [k ]
350410 if isinstance (v , dict ):
@@ -369,6 +429,8 @@ def display_dict(d, padding):
369429 display_dict (attrs , padding )
370430
371431 else :
432+ if TYPE_CHECKING :
433+ assert isinstance (obj , gitlab .base .RESTObject )
372434 if obj ._id_attr :
373435 id = getattr (obj , obj ._id_attr )
374436 print ("%s: %s" % (obj ._id_attr .replace ("_" , "-" ), id ))
@@ -383,7 +445,12 @@ def display_dict(d, padding):
383445 line = line [:76 ] + "..."
384446 print (line )
385447
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 :
387454 verbose = kwargs .get ("verbose" , False )
388455 for obj in data :
389456 if isinstance (obj , gitlab .base .RESTObject ):
@@ -393,14 +460,28 @@ def display_list(self, data, fields, **kwargs):
393460 print ("" )
394461
395462
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 )
401482 data = g_cli ()
402483
403- printer = PRINTERS [output ]()
484+ printer : Union [ JSONPrinter , LegacyPrinter , YAMLPrinter ] = PRINTERS [output ]()
404485
405486 if isinstance (data , dict ):
406487 printer .display (data , verbose = True , obj = data )
0 commit comments