2019-07-26 10:56:31 +02:00
# Copyright (C) 2018-2019 Team tiramisu (see AUTHORS for all contributors)
2018-11-29 22:52:20 +01:00
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2019-04-17 19:16:43 +02:00
from typing import Union , List , Dict , Tuple , Optional , Any
2024-07-30 11:29:10 +02:00
from argparse import ArgumentParser , Namespace , SUPPRESS , _HelpAction , HelpFormatter , ArgumentDefaultsHelpFormatter
2019-04-02 21:02:08 +02:00
from copy import copy
2019-04-09 07:28:11 +02:00
from gettext import gettext as _
2019-04-02 21:02:08 +02:00
2024-07-30 11:29:10 +02:00
#try:
from tiramisu import Config
2024-08-07 08:23:05 +02:00
from tiramisu . error import PropertiesOptionError , LeadershipError , ConfigError
2024-07-30 11:29:10 +02:00
#except ImportError:
# Config = None
# from tiramisu_api.error import PropertiesOptionError
# LeadershipError = ValueError
2019-01-10 09:55:45 +01:00
try :
2020-03-16 15:34:51 +01:00
from tiramisu_api import Config as ConfigJson
2019-01-10 09:55:45 +01:00
if Config is None :
Config = ConfigJson
2019-08-22 15:58:34 +02:00
except ImportError :
2019-01-10 09:55:45 +01:00
ConfigJson = Config
2018-11-29 22:10:08 +01:00
2024-07-30 11:29:10 +02:00
def get_choice_list ( config , properties , display ) :
2019-08-03 10:33:45 +02:00
def convert ( choice ) :
if isinstance ( choice , int ) :
return str ( choice )
return choice
2024-08-07 08:23:05 +02:00
choices = [ convert ( choice ) for choice in config . value . list ( ) if choice != ' ' and choice is not None ]
2019-08-03 09:06:27 +02:00
if display :
choices = ' {{ {} }} ' . format ( ' , ' . join ( choices ) )
if ' mandatory ' not in properties :
2019-08-22 15:58:34 +02:00
choices = ' [ {} ] ' . format ( choices )
2019-08-03 09:06:27 +02:00
return choices
2018-11-29 22:10:08 +01:00
class TiramisuNamespace ( Namespace ) :
2019-04-17 19:16:43 +02:00
def __init__ ( self ,
2019-07-26 10:56:31 +02:00
config : Config ,
root : Optional [ str ] ) - > None :
2019-04-17 19:16:43 +02:00
super ( ) . __setattr__ ( ' _config ' , config )
2019-07-26 10:56:31 +02:00
super ( ) . __setattr__ ( ' _root ' , root )
2019-04-17 19:16:43 +02:00
super ( ) . __setattr__ ( ' list_force_no ' , { } )
2019-07-27 18:51:16 +02:00
super ( ) . __setattr__ ( ' list_force_del ' , { } )
2019-08-03 09:06:27 +02:00
super ( ) . __setattr__ ( ' arguments ' , { } )
2019-04-17 19:16:43 +02:00
self . _populate ( )
super ( ) . __init__ ( )
def _populate ( self ) - > None :
2019-07-26 10:56:31 +02:00
if self . _root is None :
config = self . _config
else :
config = self . _config . option ( self . _root )
2024-07-30 11:29:10 +02:00
self . _parse ( config . value . get ( ) )
def _parse ( self , subconfig ) :
for option , value in subconfig . items ( ) :
if option . isoptiondescription ( ) :
self . _parse ( value )
elif not option . issymlinkoption ( ) :
if value == [ ] and option . ismulti ( ) :
value = None
super ( ) . __setattr__ ( option . path ( ) , value )
2018-11-29 22:10:08 +01:00
2019-04-17 19:16:43 +02:00
def __setattr__ ( self ,
key : str ,
2024-07-30 11:29:10 +02:00
value : Any ,
) - > None :
2019-04-17 19:16:43 +02:00
if key in self . list_force_no :
true_key = self . list_force_no [ key ]
2019-07-27 18:51:16 +02:00
elif key in self . list_force_del :
true_key = self . list_force_del [ key ]
2019-04-17 19:16:43 +02:00
else :
true_key = key
option = self . _config . option ( true_key )
2024-07-30 11:29:10 +02:00
if option . isfollower ( ) :
2019-04-17 19:16:43 +02:00
_setattr = self . _setattr_follower
2024-07-30 11:29:10 +02:00
if not value [ 0 ] . isdecimal ( ) :
raise ValueError ( ' index must be a number, not {} ' . format ( value [ 0 ] ) )
index = int ( value [ 0 ] )
option = self . _config . option ( true_key , index )
2019-04-17 19:16:43 +02:00
true_value = ' , ' . join ( value [ 1 : ] )
else :
_setattr = self . _setattr
true_value = value
2024-07-30 11:29:10 +02:00
if option . type ( ) == ' choice ' :
2019-08-03 09:06:27 +02:00
# HACK if integer in choice
values = option . value . list ( )
if isinstance ( value , list ) :
int_value = [ ]
for val in value :
if isinstance ( val , str ) and val . isdigit ( ) :
int_val = int ( val )
if int_val in values :
val = int_val
int_value . append ( val )
value = int_value
elif value not in values and isinstance ( value , str ) and value . isdigit ( ) :
int_value = int ( value )
if int_value in values :
value = int_value
2019-04-17 19:16:43 +02:00
try :
2019-07-27 18:51:16 +02:00
if key in self . list_force_del :
option . value . pop ( value )
else :
_setattr ( option , true_key , key , value )
2019-04-17 19:16:43 +02:00
except ValueError as err :
2024-07-30 11:29:10 +02:00
if option . type ( ) == ' choice ' :
2019-08-03 09:06:27 +02:00
values = option . value . list ( )
2020-04-09 07:52:17 +02:00
display_value = ' '
2019-08-03 09:06:27 +02:00
if isinstance ( true_value , list ) :
for val in value :
if val not in values :
display_value = val
break
else :
display_value = true_value
2019-08-03 10:33:45 +02:00
choices = get_choice_list ( option , option . property . get ( ) , False )
2019-08-23 16:22:34 +02:00
raise ValueError ( " argument {} : invalid choice: ' {} ' (choose from {} ) " . format ( self . arguments [ key ] , display_value , ' , ' . join ( [ f " ' { val } ' " for val in choices ] ) ) )
2019-04-17 19:16:43 +02:00
else :
raise err
2018-11-29 22:10:08 +01:00
2019-04-17 19:16:43 +02:00
def _setattr ( self ,
option : ' Option ' ,
true_key : str ,
key : str ,
value : Any ) - > None :
2024-07-30 11:29:10 +02:00
if option . ismulti ( ) and \
2019-04-17 19:16:43 +02:00
value is not None and \
not isinstance ( value , list ) :
2018-11-29 22:10:08 +01:00
value = [ value ]
2019-08-23 16:22:34 +02:00
try :
option . value . set ( value )
except PropertiesOptionError :
raise AttributeError ( ' unrecognized arguments: {} ' . format ( self . arguments [ key ] ) )
2018-11-29 22:10:08 +01:00
2019-04-17 19:16:43 +02:00
def _setattr_follower ( self ,
option : ' Option ' ,
true_key : str ,
key : str ,
value : Any ) - > None :
index = int ( value [ 0 ] )
2024-07-30 11:29:10 +02:00
if option . type ( ) == ' boolean ' :
2019-04-17 19:16:43 +02:00
value = key not in self . list_force_no
2024-07-30 11:29:10 +02:00
elif option . issubmulti ( ) :
2019-04-17 19:16:43 +02:00
value = value [ 1 : ]
else :
value = value [ 1 ]
self . _config . option ( true_key , index ) . value . set ( value )
2018-11-29 22:10:08 +01:00
2019-07-26 21:35:22 +02:00
class TiramisuHelpFormatter :
2019-04-01 21:08:41 +02:00
def _get_default_metavar_for_optional ( self ,
action ) :
ret = super ( ) . _get_default_metavar_for_optional ( action )
if ' . ' in ret :
2019-07-26 10:56:31 +02:00
ret = ret . rsplit ( ' . ' , 1 ) [ 1 ]
2019-04-01 21:08:41 +02:00
return ret
2019-07-26 21:35:22 +02:00
class _Section ( HelpFormatter . _Section ) :
2019-07-26 15:17:36 +02:00
def format_help ( self ) :
# Remove empty OD
if self . formatter . remove_empty_od and \
len ( self . items ) == 1 and \
self . items [ 0 ] [ 0 ] . __name__ == ' _format_text ' :
return ' '
return super ( ) . format_help ( )
2019-04-01 21:08:41 +02:00
2019-07-26 21:35:22 +02:00
2019-01-16 09:20:23 +01:00
class _TiramisuHelpAction ( _HelpAction ) :
needs = False
def __call__ ( self , * args , * * kwargs ) :
_TiramisuHelpAction . needs = True
def display ( self , parser ) :
_HelpAction . __call__ ( self , parser , None , None )
2019-04-17 19:16:43 +02:00
class _BuildKwargs :
def __init__ ( self ,
name : str ,
option : ' Option ' ,
cmdlineparser : ' TiramisuCmdlineParser ' ,
properties : List [ str ] ,
2019-07-27 18:51:16 +02:00
force_no : bool ,
2019-07-30 08:48:46 +02:00
force_del : bool ,
2024-08-09 11:18:16 +02:00
add_extra_options : bool ,
2019-07-30 08:48:46 +02:00
display_modified_value : bool ,
not_display : bool ) - > None :
2019-04-17 19:16:43 +02:00
self . kwargs = { }
self . cmdlineparser = cmdlineparser
self . properties = properties
self . force_no = force_no
2019-07-27 18:51:16 +02:00
self . force_del = force_del
2024-08-09 11:18:16 +02:00
if ( ( not self . force_no or not add_extra_options ) or ( not_display and not display_modified_value ) ) and not self . force_del :
if self . force_no :
description = option . information . get ( ' negative_description ' , None )
else :
description = None
if description is None :
description = option . description ( )
2019-07-29 22:10:40 +02:00
self . kwargs [ ' help ' ] = description
2019-04-17 19:16:43 +02:00
if ' positional ' not in self . properties :
is_short_name = self . cmdlineparser . _is_short_name ( name , ' longargument ' in self . properties )
if self . force_no :
ga_name = self . gen_argument_name ( name , is_short_name )
2019-07-30 21:50:48 +02:00
ga_path = self . gen_argument_name ( option . path ( ) , is_short_name )
self . cmdlineparser . namespace . list_force_no [ ga_path ] = option . path ( )
2019-07-27 18:51:16 +02:00
elif self . force_del :
ga_name = self . gen_argument_name ( name , is_short_name )
2019-07-30 21:50:48 +02:00
ga_path = self . gen_argument_name ( option . path ( ) , is_short_name )
self . cmdlineparser . namespace . list_force_del [ ga_path ] = option . path ( )
2019-04-17 19:16:43 +02:00
else :
ga_name = name
self . kwargs [ ' dest ' ] = self . gen_argument_name ( option . path ( ) , False )
2019-08-03 09:06:27 +02:00
argument = self . cmdlineparser . _gen_argument ( ga_name , is_short_name )
self . cmdlineparser . namespace . arguments [ option . path ( ) ] = argument
self . args = [ argument ]
2019-04-17 19:16:43 +02:00
else :
2019-08-03 09:06:27 +02:00
self . cmdlineparser . namespace . arguments [ option . path ( ) ] = option . path ( )
2019-04-17 19:16:43 +02:00
self . args = [ option . path ( ) ]
def __setitem__ ( self ,
key : str ,
value : Any ) - > None :
self . kwargs [ key ] = value
def add_argument ( self ,
option : ' Option ' ) :
is_short_name = self . cmdlineparser . _is_short_name ( option . name ( ) , ' longargument ' in self . properties )
if self . force_no :
name = self . gen_argument_name ( option . name ( ) , is_short_name )
2019-07-27 18:51:16 +02:00
elif self . force_del :
name = self . gen_argument_name ( option . name ( ) , is_short_name )
2019-04-17 19:16:43 +02:00
else :
name = option . name ( )
2019-08-03 09:06:27 +02:00
argument = self . cmdlineparser . _gen_argument ( name , is_short_name )
self . cmdlineparser . namespace . arguments [ option . path ( ) ] = argument
self . args . insert ( 0 , argument )
2019-04-17 19:16:43 +02:00
def gen_argument_name ( self , name , is_short_name ) :
if self . force_no :
if is_short_name :
prefix = ' n '
else :
prefix = ' no- '
if ' . ' in name :
sname = name . rsplit ( ' . ' , 1 )
name = sname [ 0 ] + ' . ' + prefix + sname [ 1 ]
else :
name = prefix + name
2019-07-27 18:51:16 +02:00
if self . force_del :
if is_short_name :
prefix = ' p '
else :
prefix = ' pop- '
if ' . ' in name :
sname = name . rsplit ( ' . ' , 1 )
name = sname [ 0 ] + ' . ' + prefix + sname [ 1 ]
else :
name = prefix + name
2019-04-17 19:16:43 +02:00
return name
def get ( self ) - > Tuple [ Dict ] :
return self . args , self . kwargs
2018-11-30 18:47:16 +01:00
class TiramisuCmdlineParser ( ArgumentParser ) :
2019-01-10 09:55:45 +01:00
def __init__ ( self ,
2019-01-16 09:28:29 +01:00
config : Union [ Config , ConfigJson ] ,
2019-01-10 09:55:45 +01:00
* args ,
2019-07-26 10:56:31 +02:00
root : str = None ,
2019-01-16 09:20:23 +01:00
fullpath : bool = True ,
2019-07-26 15:17:36 +02:00
remove_empty_od : bool = False ,
2019-07-30 06:58:16 +02:00
display_modified_value : bool = True ,
2024-07-30 11:29:10 +02:00
formatter_class = ArgumentDefaultsHelpFormatter ,
2019-08-23 16:22:34 +02:00
unrestraint : bool = False ,
2024-08-07 08:23:05 +02:00
add_extra_options : bool = True ,
2024-07-30 11:29:10 +02:00
short_name_max_len : int = 1 ,
2019-01-16 09:28:29 +01:00
_forhelp : bool = False ,
2019-01-10 09:55:45 +01:00
* * kwargs ) :
2024-07-30 11:29:10 +02:00
if not _forhelp :
unrestraint = True
2019-01-16 09:20:23 +01:00
self . fullpath = fullpath
2019-01-16 09:28:29 +01:00
self . config = config
2019-07-26 10:56:31 +02:00
self . root = root
2019-07-26 15:17:36 +02:00
self . remove_empty_od = remove_empty_od
2019-08-23 16:22:34 +02:00
self . unrestraint = unrestraint
2024-08-07 08:23:05 +02:00
self . add_extra_options = add_extra_options
2019-07-30 06:58:16 +02:00
self . display_modified_value = display_modified_value
2024-07-30 11:29:10 +02:00
self . short_name_max_len = short_name_max_len
2019-07-26 21:35:22 +02:00
if TiramisuHelpFormatter not in formatter_class . __mro__ :
formatter_class = type ( ' TiramisuHelpFormatter ' , ( TiramisuHelpFormatter , formatter_class ) , { } )
formatter_class . remove_empty_od = self . remove_empty_od
kwargs [ ' formatter_class ' ] = formatter_class
2019-08-23 16:22:34 +02:00
if not _forhelp and self . unrestraint :
subconfig = self . config . unrestraint
else :
subconfig = self . config
2019-07-26 10:56:31 +02:00
if self . root is None :
2024-07-30 11:29:10 +02:00
subconfig = subconfig
2019-07-26 10:56:31 +02:00
else :
2019-08-23 16:22:34 +02:00
subconfig = subconfig . option ( self . root )
2019-07-26 10:56:31 +02:00
self . namespace = TiramisuNamespace ( self . config , self . root )
2018-11-29 22:10:08 +01:00
super ( ) . __init__ ( * args , * * kwargs )
2019-01-16 09:20:23 +01:00
self . register ( ' action ' , ' help ' , _TiramisuHelpAction )
2019-01-16 09:28:29 +01:00
self . _config_to_argparser ( _forhelp ,
2019-07-26 10:56:31 +02:00
subconfig ,
2024-07-30 11:29:10 +02:00
self . root ,
)
2019-01-16 09:20:23 +01:00
def _pop_action_class ( self , kwargs , default = None ) :
ret = super ( ) . _pop_action_class ( kwargs , default )
if kwargs . get ( ' action ' ) != ' help ' and kwargs . get ( ' dest ' ) != ' help ' :
return ret
return _TiramisuHelpAction
2018-11-29 22:10:08 +01:00
2019-01-10 09:55:45 +01:00
def _match_arguments_partial ( self ,
actions ,
arg_string_pattern ) :
2018-11-29 22:10:08 +01:00
# used only when check first proposal for first value
# we have to remove all actions with propertieserror
# so only first settable option will be returned
actions_pop = [ ]
for idx , action in enumerate ( actions ) :
2019-01-10 09:55:45 +01:00
if self . config . option ( action . dest ) . property . get ( only_raises = True ) :
2018-11-29 22:10:08 +01:00
actions_pop . append ( idx )
else :
break
for idx in actions_pop :
actions . pop ( 0 )
return super ( ) . _match_arguments_partial ( actions , arg_string_pattern )
2019-04-17 19:16:43 +02:00
def _is_short_name ( self , name , longargument ) :
2024-07-30 11:29:10 +02:00
return len ( name ) < = self . short_name_max_len and not longargument
2019-01-16 09:20:23 +01:00
2019-04-17 19:16:43 +02:00
def _gen_argument ( self , name , is_short_name ) :
if is_short_name :
return self . prefix_chars + name
return self . prefix_chars * 2 + name
def _parse_known_args ( self , args = None , namespace = None ) :
try :
namespace_ , args_ = super ( ) . _parse_known_args ( args , namespace )
2019-08-23 16:22:34 +02:00
except ( ValueError , LeadershipError , AttributeError ) as err :
2019-04-17 19:16:43 +02:00
self . error ( err )
2019-01-16 09:20:23 +01:00
if args != args_ and args_ and args_ [ 0 ] . startswith ( self . prefix_chars ) :
# option that was disabled are no more disable
# so create a new parser
2019-01-16 09:28:29 +01:00
new_parser = TiramisuCmdlineParser ( self . config ,
self . prog ,
2019-07-26 10:56:31 +02:00
root = self . root ,
2019-07-26 15:17:36 +02:00
remove_empty_od = self . remove_empty_od ,
2019-07-30 06:58:16 +02:00
display_modified_value = self . display_modified_value ,
2019-07-26 21:35:22 +02:00
formatter_class = self . formatter_class ,
2019-07-26 16:39:01 +02:00
epilog = self . epilog ,
2019-07-28 22:44:17 +02:00
description = self . description ,
2019-08-23 16:22:34 +02:00
unrestraint = self . unrestraint ,
2024-08-07 08:23:05 +02:00
add_extra_options = self . add_extra_options ,
2024-07-30 11:29:10 +02:00
short_name_max_len = self . short_name_max_len ,
2019-01-16 09:28:29 +01:00
fullpath = self . fullpath )
2019-07-28 09:15:31 +02:00
namespace_ , args_ = new_parser . _parse_known_args ( args_ , new_parser . namespace )
2019-01-16 09:20:23 +01:00
else :
if self . _registries [ ' action ' ] [ ' help ' ] . needs :
# display help only when all variables assignemnt are done
self . _registries [ ' action ' ] [ ' help ' ] . needs = False
helper = self . _registries [ ' action ' ] [ ' help ' ] ( None )
helper . display ( self )
return namespace_ , args_
2018-11-29 22:10:08 +01:00
def add_argument ( self , * args , * * kwargs ) :
if args == ( ' -h ' , ' --help ' ) :
super ( ) . add_argument ( * args , * * kwargs )
else :
2019-04-09 07:28:11 +02:00
raise NotImplementedError ( _ ( ' do not use add_argument ' ) )
2018-11-29 22:10:08 +01:00
2019-01-16 09:28:29 +01:00
def add_arguments ( self , * args , * * kwargs ) :
2019-04-09 07:28:11 +02:00
raise NotImplementedError ( _ ( ' do not use add_argument ' ) )
2019-01-16 09:28:29 +01:00
2018-12-01 08:28:35 +01:00
def add_subparsers ( self , * args , * * kwargs ) :
2019-04-09 07:28:11 +02:00
raise NotImplementedError ( _ ( ' do not use add_subparsers ' ) )
2018-12-01 08:28:35 +01:00
2019-04-17 19:16:43 +02:00
def _option_is_not_default ( self ,
properties ,
type ,
name ,
value ) :
if ' positional ' not in properties :
is_short_name = self . _is_short_name ( name , ' longargument ' in properties )
self . prog + = ' {} ' . format ( self . _gen_argument ( name , is_short_name ) )
if type != ' boolean ' :
2019-07-28 09:15:31 +02:00
if isinstance ( value , list ) :
for val in value :
2019-08-22 15:58:34 +02:00
self . prog + = ' " {} " ' . format ( val )
2019-07-28 09:15:31 +02:00
else :
2019-08-22 15:58:34 +02:00
self . prog + = ' " {} " ' . format ( value )
2019-04-17 19:16:43 +02:00
def _config_list ( self ,
config : Config ,
prefix : Optional [ str ] ,
_forhelp : bool ,
2019-07-27 18:51:16 +02:00
group , level ) :
2024-08-07 08:23:05 +02:00
obj = None
2024-07-30 11:29:10 +02:00
for obj in config :
2019-04-17 19:16:43 +02:00
# do not display frozen option
2024-07-30 11:29:10 +02:00
if ' frozen ' in obj . property . get ( ) :
2019-04-17 19:16:43 +02:00
continue
2024-07-30 11:29:10 +02:00
if obj . isoptiondescription ( ) :
2019-04-17 19:16:43 +02:00
if _forhelp :
2024-07-30 11:29:10 +02:00
description = obj . description ( )
if description == obj . name ( ) :
description = None
newgroup = self . add_argument_group ( obj . path ( ) , description )
2019-07-26 10:56:31 +02:00
else :
newgroup = group
2019-04-17 19:16:43 +02:00
if prefix :
2024-07-30 11:29:10 +02:00
prefix_ = prefix + ' . ' + obj . name ( )
2019-04-17 19:16:43 +02:00
else :
2024-07-30 11:29:10 +02:00
prefix_ = obj . path ( )
2019-07-27 18:51:16 +02:00
self . _config_to_argparser ( _forhelp , obj , prefix_ , newgroup , level + 1 )
2024-08-07 08:23:05 +02:00
elif self . add_extra_options and obj . type ( ) == ' boolean ' and not obj . issymlinkoption ( ) :
2024-07-30 11:29:10 +02:00
if not obj . isleader ( ) :
2019-07-27 18:51:16 +02:00
yield obj , False , None
yield obj , True , None
else :
yield obj , False , False
yield obj , False , True
yield obj , True , None
2024-08-07 08:23:05 +02:00
elif self . add_extra_options and obj . isleader ( ) :
2019-07-27 18:51:16 +02:00
yield obj , None , False
yield obj , None , True
2019-04-02 21:02:08 +02:00
else :
2024-08-09 11:18:16 +02:00
if not obj . issymlinkoption ( ) and obj . type ( ) == ' boolean ' and obj . value . get ( ) is True :
negative_description = obj . information . get ( ' negative_description ' , None )
if _forhelp and not negative_description :
raise ValueError ( _ ( f ' the boolean " { obj . path ( ) } " cannot have a default value to " True " with option add_extra_options if there is no negative_description ' ) )
yield obj , True , None
else :
yield obj , None , None
2024-08-07 08:23:05 +02:00
if obj is not None and not obj . isoptiondescription ( ) and obj . isleader ( ) :
# no follower found, search if there is a symlink
for sobj in config . list ( uncalculated = True ) :
try :
if sobj . issymlinkoption ( ) and sobj . option ( ) . isleader ( ) :
yield sobj , None , None
except ConfigError :
pass
2019-01-16 17:44:49 +01:00
2018-12-01 08:28:35 +01:00
def _config_to_argparser ( self ,
2019-01-10 09:55:45 +01:00
_forhelp : bool ,
config ,
2019-07-26 10:56:31 +02:00
prefix : Optional [ str ] ,
2019-07-27 18:51:16 +02:00
group = None ,
level = 0 ) - > None :
2019-01-10 09:55:45 +01:00
if group is None :
group = super ( )
2018-11-29 22:10:08 +01:00
actions = { }
2019-04-17 19:16:43 +02:00
leadership_len = None
2019-07-28 09:15:31 +02:00
options_is_not_default = { }
2024-07-30 11:29:10 +02:00
for option , force_no , force_del in self . _config_list ( config , prefix , _forhelp , group , level ) :
2019-07-26 10:56:31 +02:00
name = option . name ( )
if name . startswith ( self . prefix_chars ) :
raise ValueError ( _ ( ' name cannot startswith " {} " ' ) . format ( self . prefix_chars ) )
if option . issymlinkoption ( ) :
2024-07-30 11:29:10 +02:00
symlink_name = option . option ( ) . name ( )
2019-07-28 09:15:31 +02:00
if symlink_name in options_is_not_default :
options_is_not_default [ symlink_name ] [ ' name ' ] = name
2019-07-26 10:56:31 +02:00
if symlink_name in actions :
for action in actions [ symlink_name ] :
action . add_argument ( option )
continue
2019-07-27 18:51:16 +02:00
if force_del :
value = None
2024-08-09 11:18:16 +02:00
# elif force_no:
# value = not option.value.get()
2019-07-27 18:51:16 +02:00
elif option . isleader ( ) :
2024-07-30 11:29:10 +02:00
value = option . value . get ( )
2019-04-17 19:16:43 +02:00
leadership_len = len ( value )
elif option . isfollower ( ) :
2024-08-09 11:18:16 +02:00
if _forhelp :
value = option . value . defaultmulti ( )
else :
value = [ ]
try :
for index in range ( leadership_len ) :
value . append ( self . config . option ( option . path ( ) , index ) . value . get ( ) )
except :
value = None
2019-04-17 19:16:43 +02:00
else :
2024-07-30 11:29:10 +02:00
value = option . value . get ( )
2019-02-27 07:32:32 +01:00
if self . fullpath and prefix :
name = prefix + ' . ' + name
2024-07-30 11:29:10 +02:00
properties = option . property . get ( )
not_display = not option . isfollower ( ) and not option . owner . isdefault ( ) and value is not None
2024-08-09 11:18:16 +02:00
kwargs = _BuildKwargs ( name , option , self , properties , force_no , force_del , self . add_extra_options , self . display_modified_value , not_display )
2019-07-30 08:48:46 +02:00
if _forhelp and not_display and ( ( value is not False and not force_no ) or ( value is False and force_no ) ) :
2019-07-28 09:15:31 +02:00
options_is_not_default [ option . name ( ) ] = { ' properties ' : properties ,
' type ' : option . type ( ) ,
' name ' : name ,
2024-07-30 11:29:10 +02:00
' value ' : value ,
}
2019-07-30 06:58:16 +02:00
if not self . display_modified_value :
continue
2024-08-09 11:18:16 +02:00
if force_no :
default = False
else :
default = option . value . default ( )
if isinstance ( default , list ) :
str_default_value = ' , ' . join ( [ str ( v ) for v in default ] )
else :
str_default_value = default
2019-07-28 09:15:31 +02:00
if ' positional ' in properties :
if option . type ( ) == ' boolean ' :
raise ValueError ( _ ( ' boolean option must not be positional ' ) )
if not ' mandatory ' in properties :
raise ValueError ( ' " positional " argument must be " mandatory " too ' )
if _forhelp :
2024-08-09 11:18:16 +02:00
kwargs [ ' default ' ] = str_default_value
2019-02-27 07:32:32 +01:00
else :
2019-07-28 09:15:31 +02:00
kwargs [ ' default ' ] = value
kwargs [ ' nargs ' ] = ' ? '
else :
2024-07-30 11:29:10 +02:00
if _forhelp and not option . isleader ( ) :
if default not in [ None , [ ] ] :
2024-08-09 11:18:16 +02:00
kwargs [ ' default ' ] = str_default_value
2024-07-30 11:29:10 +02:00
else :
kwargs [ ' default ' ] = SUPPRESS
else :
kwargs [ ' default ' ] = SUPPRESS
2019-07-28 09:15:31 +02:00
if _forhelp and ' mandatory ' in properties :
kwargs [ ' required ' ] = True
if not force_del and option . type ( ) == ' boolean ' :
if not option . isfollower ( ) :
if ' storefalse ' in properties :
if force_no :
2019-07-27 18:51:16 +02:00
action = ' store_true '
else :
2019-07-28 09:15:31 +02:00
action = ' store_false '
elif force_no :
action = ' store_false '
2019-04-17 19:16:43 +02:00
else :
2019-07-28 09:15:31 +02:00
action = ' store_true '
kwargs [ ' action ' ] = action
else :
2019-07-27 18:51:16 +02:00
kwargs [ ' metavar ' ] = ' INDEX '
2019-07-28 09:15:31 +02:00
if option . type ( ) != ' boolean ' or force_del :
if not force_del :
if _forhelp :
2024-07-30 11:29:10 +02:00
value = option . value . default ( )
2019-07-28 09:15:31 +02:00
if value not in [ None , [ ] ] :
#kwargs['default'] = kwargs['const'] = option.default()
#kwargs['action'] = 'store_const'
kwargs [ ' nargs ' ] = ' ? '
if not option . isfollower ( ) and option . ismulti ( ) :
if _forhelp and ' mandatory ' in properties :
kwargs [ ' nargs ' ] = ' + '
else :
kwargs [ ' nargs ' ] = ' * '
if option . isfollower ( ) and not option . type ( ) == ' boolean ' :
metavar = option . name ( ) . upper ( )
if option . issubmulti ( ) :
kwargs [ ' nargs ' ] = ' + '
else :
kwargs [ ' nargs ' ] = 2
if _forhelp and ' mandatory ' not in properties :
2019-08-22 15:58:34 +02:00
metavar = ' [ {} ] ' . format ( metavar )
2019-08-03 10:33:45 +02:00
if option . type ( ) == ' choice ' :
2019-08-03 09:06:27 +02:00
# do not manage choice with argparse there is problem with integer problem
2024-07-30 11:29:10 +02:00
kwargs [ ' metavar ' ] = ( ' INDEX ' , get_choice_list ( option , properties , True ) )
2019-04-17 19:16:43 +02:00
else :
2019-07-28 09:15:31 +02:00
kwargs [ ' metavar ' ] = ( ' INDEX ' , metavar )
if force_del :
kwargs [ ' metavar ' ] = ' INDEX '
kwargs [ ' type ' ] = int
elif option . type ( ) == ' string ' :
pass
elif option . type ( ) == ' integer ' or option . type ( ) == ' boolean ' :
# when boolean we are here only if follower
kwargs [ ' type ' ] = int
if _forhelp and option . type ( ) == ' boolean ' :
kwargs [ ' metavar ' ] = ' INDEX '
kwargs [ ' nargs ' ] = 1
2019-08-03 10:33:45 +02:00
elif option . type ( ) == ' choice ' and not option . isfollower ( ) :
2019-08-03 09:06:27 +02:00
# do not manage choice with argparse there is problem with integer problem
2024-07-30 11:29:10 +02:00
kwargs [ ' choices ' ] = get_choice_list ( option , properties , False )
2020-03-20 22:19:10 +01:00
elif option . type ( ) == ' float ' :
kwargs [ ' type ' ] = float
2019-07-28 09:15:31 +02:00
else :
pass
actions . setdefault ( option . name ( ) , [ ] ) . append ( kwargs )
2024-08-29 08:18:10 +02:00
2019-07-28 09:15:31 +02:00
for option_is_not_default in options_is_not_default . values ( ) :
self . _option_is_not_default ( * * option_is_not_default )
2019-04-02 21:02:08 +02:00
for values in actions . values ( ) :
2019-04-17 19:16:43 +02:00
for value in values :
args , kwargs = value . get ( )
2019-04-02 21:02:08 +02:00
group . add_argument ( * args , * * kwargs )
2018-11-29 22:10:08 +01:00
2024-08-29 08:18:10 +02:00
# def _valid_mandatory(self):
# pass
#
2019-01-17 09:40:07 +01:00
def parse_args ( self ,
* args ,
valid_mandatory = True ,
* * kwargs ) :
2019-04-17 19:16:43 +02:00
kwargs [ ' namespace ' ] = self . namespace
2018-11-29 22:10:08 +01:00
try :
2018-12-01 09:53:31 +01:00
namespaces = super ( ) . parse_args ( * args , * * kwargs )
2018-11-29 22:10:08 +01:00
except PropertiesOptionError as err :
2024-08-29 08:18:10 +02:00
name = err . _subconfig . path
2019-01-10 09:55:45 +01:00
properties = self . config . option ( name ) . property . get ( )
2019-04-01 21:08:41 +02:00
if self . fullpath and ' positional ' not in properties :
2018-12-01 09:53:31 +01:00
if len ( name ) == 1 and ' longargument ' not in properties :
name = self . prefix_chars + name
else :
name = self . prefix_chars * 2 + name
2018-12-01 08:28:35 +01:00
if err . proptype == [ ' mandatory ' ] :
self . error ( ' the following arguments are required: {} ' . format ( name ) )
2018-11-29 22:10:08 +01:00
else :
2018-12-01 09:53:31 +01:00
self . error ( ' unrecognized arguments: {} ' . format ( name ) )
2019-01-17 09:40:07 +01:00
if valid_mandatory :
2019-04-17 19:16:43 +02:00
errors = [ ]
2024-07-30 11:29:10 +02:00
for option in self . config . value . mandatory ( ) :
properties = option . property . get ( )
if not option . isfollower ( ) :
2019-04-17 19:16:43 +02:00
if ' positional ' not in properties :
2024-07-30 11:29:10 +02:00
if self . fullpath :
name = option . path ( )
2019-04-17 19:16:43 +02:00
else :
2024-07-30 11:29:10 +02:00
name = option . name ( )
is_short_name = self . _is_short_name ( name , ' longargument ' in option . property . get ( ) )
2019-04-17 19:16:43 +02:00
args = self . _gen_argument ( name , is_short_name )
2019-01-28 17:05:50 +01:00
else :
2024-07-30 11:29:10 +02:00
args = option . path ( )
2019-01-17 09:40:07 +01:00
else :
2019-04-17 19:16:43 +02:00
if ' positional ' not in properties :
2024-07-30 11:29:10 +02:00
args = self . _gen_argument ( option . path ( ) , False )
2019-04-17 19:16:43 +02:00
else :
2024-07-30 11:29:10 +02:00
args = option . path ( )
2019-04-01 21:08:41 +02:00
if not self . fullpath and ' . ' in args :
args = args . rsplit ( ' . ' , 1 ) [ 1 ]
2019-04-17 19:16:43 +02:00
if ' positional ' not in properties :
args = self . _gen_argument ( args , False )
errors . append ( args )
if errors :
self . error ( ' the following arguments are required: {} ' . format ( ' , ' . join ( errors ) ) )
2018-11-29 22:10:08 +01:00
return namespaces
2019-01-10 09:55:45 +01:00
def format_usage ( self ,
* args ,
* * kwargs ) :
2019-01-16 09:28:29 +01:00
help_formatter = TiramisuCmdlineParser ( self . config ,
self . prog ,
2019-07-26 10:56:31 +02:00
root = self . root ,
2019-01-16 09:28:29 +01:00
fullpath = self . fullpath ,
2019-07-26 15:17:36 +02:00
remove_empty_od = self . remove_empty_od ,
2019-07-30 06:58:16 +02:00
display_modified_value = self . display_modified_value ,
2019-07-26 21:35:22 +02:00
formatter_class = self . formatter_class ,
2024-08-07 08:23:05 +02:00
add_extra_options = self . add_extra_options ,
2024-07-30 11:29:10 +02:00
short_name_max_len = self . short_name_max_len ,
2019-07-26 16:39:01 +02:00
epilog = self . epilog ,
2019-07-28 22:44:17 +02:00
description = self . description ,
2019-01-16 09:28:29 +01:00
_forhelp = True )
2019-01-16 09:20:23 +01:00
return super ( TiramisuCmdlineParser , help_formatter ) . format_usage ( * args , * * kwargs )
2018-12-01 08:28:35 +01:00
2019-04-02 08:49:36 +02:00
def format_help ( self ) :
2019-01-16 09:28:29 +01:00
help_formatter = TiramisuCmdlineParser ( self . config ,
self . prog ,
2019-07-26 10:56:31 +02:00
root = self . root ,
2019-01-16 09:28:29 +01:00
fullpath = self . fullpath ,
2019-07-26 15:17:36 +02:00
remove_empty_od = self . remove_empty_od ,
2019-07-30 06:58:16 +02:00
display_modified_value = self . display_modified_value ,
2019-07-26 21:35:22 +02:00
formatter_class = self . formatter_class ,
2024-08-07 08:23:05 +02:00
add_extra_options = self . add_extra_options ,
2024-07-30 11:29:10 +02:00
short_name_max_len = self . short_name_max_len ,
2019-07-26 16:39:01 +02:00
epilog = self . epilog ,
2019-07-28 22:44:17 +02:00
description = self . description ,
2019-01-16 09:28:29 +01:00
_forhelp = True )
2019-04-02 08:49:36 +02:00
return super ( TiramisuCmdlineParser , help_formatter ) . format_help ( )
2018-12-01 08:28:35 +01:00
2018-11-29 22:10:08 +01:00
def get_config ( self ) :
return self . config