Skip to content

Commit fd56980

Browse files
committed
- Fixed behavior of bool --X/--disable-X
- Fixed beahvore of defaults with `store_or_None` - Fixed checking defaults vs list/tuple instead of flattened value - Added checks for list values in covert comming from the defaults
1 parent fac6436 commit fd56980

File tree

2 files changed

+70
-25
lines changed

2 files changed

+70
-25
lines changed

easybuild/cli/__init__.py

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,34 +31,61 @@ def eb(ctx, other_args):
3131
for key, value in getattr(ctx, 'hidden_params', {}).items():
3232
key = key.replace('_', '-')
3333
opt = EasyBuildCliOption.OPTIONS_MAP[key]
34+
# TEST_KEYS = [
35+
# 'robot',
36+
# 'robot-paths',
37+
# 'map-toolchains',
38+
# 'search-paths',
39+
# ]
40+
# if key in TEST_KEYS:
41+
# print(f'{key.upper()}: `{value=}` `{type(value)=}` `{opt.default=}` `{opt.action=}`')
3442
if value in ['False', 'True']:
3543
value = value == 'True'
3644
if isinstance(value, bool):
37-
if value:
38-
args.append(f"--{key}")
45+
if value != opt.default:
46+
if value:
47+
args.append(f"--{key}")
48+
else:
49+
args.append(f"--disable-{key}")
3950
else:
51+
4052
if isinstance(value, (list, tuple)) and value:
4153
# Flatten nested lists if necessary
4254
if isinstance(value[0], list):
4355
value = sum(value, [])
4456
# Match the type of the option with the default to see if we need to add it
45-
if isinstance(value, list) and isinstance(opt.default, tuple):
57+
if value and isinstance(value, list) and isinstance(opt.default, tuple):
4658
value = tuple(value)
47-
if value and value != opt.default:
48-
if isinstance(value, (list, tuple)):
49-
if 'path' in opt.type:
50-
delim = os.pathsep
51-
elif 'str' in opt.type:
52-
delim = ','
53-
elif 'url' in opt.type:
54-
delim = '|'
55-
else:
56-
raise ValueError(f"Unsupported type for {key}: {opt.type}")
57-
value = delim.join(value)
59+
if value and isinstance(value, tuple) and isinstance(opt.default, list):
60+
value = list(value)
61+
value_is_default = (value == opt.default)
5862

59-
# print(f"--Adding {key}={value} to args")
60-
args.append(f"--{key}={value}")
63+
value_flattened = value
64+
if isinstance(value, (list, tuple)):
65+
if 'path' in opt.type:
66+
delim = os.pathsep
67+
elif 'str' in opt.type:
68+
delim = ','
69+
elif 'url' in opt.type:
70+
delim = '|'
71+
else:
72+
raise ValueError(f"Unsupported type for {key}: {opt.type}")
73+
value_flattened = delim.join(value)
6174

62-
args.extend(other_args)
75+
if opt.action == 'store_or_None':
76+
if value is None or value == ():
77+
continue
78+
if value_is_default:
79+
args.append(f"--{key}")
80+
else:
81+
args.append(f"--{key}={value_flattened}")
82+
elif value and not value_is_default:
83+
if value:
84+
args.append(f"--{key}={value_flattened}")
85+
else:
86+
args.append(f"--{key}")
87+
# for arg in args:
88+
# print(f"ARG: {arg}")
6389

90+
args.extend(other_args)
6491
main_with_hooks(args=args)

easybuild/cli/options/__init__.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,16 @@ def __init__(self, *args, delimiter=',', resolve_full: bool = True, **kwargs):
4242
self.resolve_full = resolve_full
4343

4444
def convert(self, value, param, ctx):
45-
if not isinstance(value, str):
45+
# logging.warning(f"{param=} convert called with `{value=}`, `{type(value)=}`")
46+
if isinstance(value, str):
47+
res = value.split(self.delimiter)
48+
elif isinstance(value, (list, tuple)):
49+
res = value
50+
else:
4651
raise click.BadParameter(f"Expected a comma-separated string, got {value}")
47-
res = value.split(self.delimiter)
4852
if self.resolve_full:
4953
res = [os.path.abspath(v) for v in res]
54+
# logging.warning(f"{param=} convert returning `{res=}`")
5055
return res
5156

5257
def shell_complete(self, ctx, param, incomplete):
@@ -83,8 +88,12 @@ def __init__(self, *args, delimiter=',', **kwargs):
8388

8489
def convert(self, value, param, ctx):
8590
if isinstance(value, str):
86-
return value.split(self.delimiter)
87-
raise click.BadParameter(f"Expected a string or a comma-separated string, got {value}")
91+
res = value.split(self.delimiter)
92+
elif isinstance(value, (list, tuple)):
93+
res = value
94+
else:
95+
raise click.BadParameter(f"Expected a string or a comma-separated string, got {value}")
96+
return res
8897

8998
def shell_complete(self, ctx, param, incomplete):
9099
last = incomplete.rsplit(self.delimiter, 1)[-1]
@@ -124,13 +133,15 @@ def __post_init__(self):
124133

125134
def to_click_option_dec(self):
126135
"""Convert OptionData to a click.Option."""
127-
decls = [f"--{self.name}"]
136+
decl = f"--{self.name}"
137+
other_decls = []
128138
if self.short:
129-
decls.insert(0, f"-{self.short}")
139+
other_decls.insert(0, f"-{self.short}")
130140

131141
kwargs = {
132142
'help': self.description,
133143
'default': self.default,
144+
'is_flag': False,
134145
'show_default': True,
135146
'type': None
136147
}
@@ -139,7 +150,6 @@ def to_click_option_dec(self):
139150
kwargs['type'] = DelimitedString(delimiter=',')
140151
kwargs['multiple'] = True
141152
elif self.type in ['pathlist', 'pathtuple']:
142-
# kwargs['type'] = DelimitedPathList(delimiter=os.pathsep)
143153
kwargs['type'] = DelimitedPathList(delimiter=',')
144154
kwargs['multiple'] = True
145155
elif self.type in ['urllist', 'urltuple']:
@@ -148,7 +158,7 @@ def to_click_option_dec(self):
148158
elif self.type == 'choice':
149159
if self.lst is None:
150160
raise ValueError(f"Choice type requires a list of choices for option {self.name}")
151-
kwargs['type'] = click.Choice(self.lst, case_sensitive=False)
161+
kwargs['type'] = click.Choice(self.lst, case_sensitive=True)
152162
elif self.type in ['int', int]:
153163
kwargs['type'] = click.INT
154164
elif self.type in ['float', float]:
@@ -159,10 +169,18 @@ def to_click_option_dec(self):
159169
if self.default is False or self.default is True:
160170
kwargs['is_flag'] = True
161171
kwargs['type'] = click.BOOL
172+
if self.action in ['store_true', 'store_false']:
173+
decl = f"--{self.name}/--disable-{self.name}"
162174
elif isinstance(self.default, (list, tuple)):
163175
kwargs['multiple'] = True
164176
kwargs['type'] = click.STRING
165177

178+
if self.action == 'store_or_None':
179+
kwargs['default'] = None
180+
kwargs['flag_value'] = self.default
181+
182+
decls = other_decls + [decl]
183+
166184
return click.option(
167185
*decls,
168186
expose_value=False,

0 commit comments

Comments
 (0)