@@ -200,11 +200,15 @@ def _populate_sub_parser_by_class(
200200mgr_cls_name = f"{ cls .__name__ } Manager"
201201mgr_cls = getattr (gitlab .v4 .objects ,mgr_cls_name )
202202
203+ action_parsers :Dict [str ,argparse .ArgumentParser ]= {}
203204for action_name in ["list" ,"get" ,"create" ,"update" ,"delete" ]:
204205if not hasattr (mgr_cls ,action_name ):
205206continue
206207
207- sub_parser_action = sub_parser .add_parser (action_name )
208+ sub_parser_action = sub_parser .add_parser (
209+ action_name ,conflict_handler = "resolve"
210+ )
211+ action_parsers [action_name ]= sub_parser_action
208212sub_parser_action .add_argument ("--sudo" ,required = False )
209213if mgr_cls ._from_parent_attrs :
210214for x in mgr_cls ._from_parent_attrs :
@@ -268,7 +272,10 @@ def _populate_sub_parser_by_class(
268272if cls .__name__ in cli .custom_actions :
269273name = cls .__name__
270274for action_name in cli .custom_actions [name ]:
271- sub_parser_action = sub_parser .add_parser (action_name )
275+ if action_name in action_parsers :
276+ sub_parser_action = action_parsers [action_name ]
277+ else :
278+ sub_parser_action = sub_parser .add_parser (action_name )
272279# Get the attributes for URL/path construction
273280if mgr_cls ._from_parent_attrs :
274281for x in mgr_cls ._from_parent_attrs :
@@ -298,13 +305,18 @@ def _populate_sub_parser_by_class(
298305if mgr_cls .__name__ in cli .custom_actions :
299306name = mgr_cls .__name__
300307for action_name in cli .custom_actions [name ]:
301- sub_parser_action = sub_parser .add_parser (action_name )
308+ if action_name in action_parsers :
309+ sub_parser_action = action_parsers [action_name ]
310+ else :
311+ sub_parser_action = sub_parser .add_parser (action_name )
302312if mgr_cls ._from_parent_attrs :
303313for x in mgr_cls ._from_parent_attrs :
304314sub_parser_action .add_argument (
305315f"--{ x .replace ('_' ,'-' )} " ,required = True
306316 )
307- sub_parser_action .add_argument ("--sudo" ,required = False )
317+ sub_parser_action .sub_parser_action .add_argument (
318+ "--sudo" ,required = False
319+ )
308320
309321required ,optional ,dummy = cli .custom_actions [name ][action_name ]
310322for x in required :
@@ -326,16 +338,15 @@ def extend_parser(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
326338subparsers .required = True
327339
328340# populate argparse for all Gitlab Object
329- classes = []
341+ classes = set ()
330342for cls in gitlab .v4 .objects .__dict__ .values ():
331343if not isinstance (cls ,type ):
332344continue
333345if issubclass (cls ,gitlab .base .RESTManager ):
334346if cls ._obj_cls is not None :
335- classes .append (cls ._obj_cls )
336- classes .sort (key = operator .attrgetter ("__name__" ))
347+ classes .add (cls ._obj_cls )
337348
338- for cls in classes :
349+ for cls in sorted ( classes , key = operator . attrgetter ( "__name__" )) :
339350arg_name = cli .cls_to_what (cls )
340351object_group = subparsers .add_parser (arg_name )
341352