Skip to content

Commit 0145d7e

Browse files
authored
CLI arg list whitespaces fix. (#369)
1 parent 136c2c7 commit 0145d7e

File tree

2 files changed

+74
-32
lines changed

2 files changed

+74
-32
lines changed

pydantic_settings/sources.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1171,9 +1171,11 @@ def _merge_parsed_list(self, parsed_list: list[str], field_name: str) -> str:
11711171
list if parsed_list and (len(parsed_list) > 1 or parsed_list[0].startswith('[')) else str
11721172
)
11731173
for val in parsed_list:
1174+
val = val.strip()
11741175
if val.startswith('[') and val.endswith(']'):
1175-
val = val[1:-1]
1176+
val = val[1:-1].strip()
11761177
while val:
1178+
val = val.strip()
11771179
if val.startswith(','):
11781180
val = self._consume_comma(val, merged_list, is_last_consumed_a_value)
11791181
is_last_consumed_a_value = False

tests/test_settings.py

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2625,8 +2625,26 @@ class Settings(BaseSettings):
26252625
assert s.n.bar == 'bar value'
26262626

26272627

2628+
def no_add_cli_arg_spaces(arg_str: str, has_quote_comma: bool = False) -> str:
2629+
return arg_str
2630+
2631+
2632+
def add_cli_arg_spaces(arg_str: str, has_quote_comma: bool = False) -> str:
2633+
arg_str = arg_str.replace('[', ' [ ')
2634+
arg_str = arg_str.replace(']', ' ] ')
2635+
arg_str = arg_str.replace('{', ' { ')
2636+
arg_str = arg_str.replace('}', ' } ')
2637+
arg_str = arg_str.replace(':', ' : ')
2638+
if not has_quote_comma:
2639+
arg_str = arg_str.replace(',', ' , ')
2640+
else:
2641+
arg_str = arg_str.replace('",', '" , ')
2642+
return f' {arg_str} '
2643+
2644+
2645+
@pytest.mark.parametrize('arg_spaces', [no_add_cli_arg_spaces, add_cli_arg_spaces])
26282646
@pytest.mark.parametrize('prefix', ['', 'child.'])
2629-
def test_cli_list_arg(prefix):
2647+
def test_cli_list_arg(prefix, arg_spaces):
26302648
class Obj(BaseModel):
26312649
val: int
26322650

@@ -2657,8 +2675,8 @@ def check_answer(cfg, prefix, expected):
26572675
assert cfg.model_dump() == expected
26582676

26592677
args: List[str] = []
2660-
args = [f'--{prefix}num_list', '[1,2]']
2661-
args += [f'--{prefix}num_list', '3,4']
2678+
args = [f'--{prefix}num_list', arg_spaces('[1,2]')]
2679+
args += [f'--{prefix}num_list', arg_spaces('3,4')]
26622680
args += [f'--{prefix}num_list', '5', f'--{prefix}num_list', '6']
26632681
cfg = Cfg(_cli_parse_args=args)
26642682
expected = {
@@ -2669,9 +2687,9 @@ def check_answer(cfg, prefix, expected):
26692687
}
26702688
check_answer(cfg, prefix, expected)
26712689

2672-
args = [f'--{prefix}obj_list', '[{"val":1},{"val":2}]']
2673-
args += [f'--{prefix}obj_list', '{"val":3},{"val":4}']
2674-
args += [f'--{prefix}obj_list', '{"val":5}', f'--{prefix}obj_list', '{"val":6}']
2690+
args = [f'--{prefix}obj_list', arg_spaces('[{"val":1},{"val":2}]')]
2691+
args += [f'--{prefix}obj_list', arg_spaces('{"val":3},{"val":4}')]
2692+
args += [f'--{prefix}obj_list', arg_spaces('{"val":5}'), f'--{prefix}obj_list', arg_spaces('{"val":6}')]
26752693
cfg = Cfg(_cli_parse_args=args)
26762694
expected = {
26772695
'num_list': None,
@@ -2681,9 +2699,9 @@ def check_answer(cfg, prefix, expected):
26812699
}
26822700
check_answer(cfg, prefix, expected)
26832701

2684-
args = [f'--{prefix}union_list', '[{"val":1},2]', f'--{prefix}union_list', '[3,{"val":4}]']
2685-
args += [f'--{prefix}union_list', '{"val":5},6', f'--{prefix}union_list', '7,{"val":8}']
2686-
args += [f'--{prefix}union_list', '{"val":9}', f'--{prefix}union_list', '10']
2702+
args = [f'--{prefix}union_list', arg_spaces('[{"val":1},2]'), f'--{prefix}union_list', arg_spaces('[3,{"val":4}]')]
2703+
args += [f'--{prefix}union_list', arg_spaces('{"val":5},6'), f'--{prefix}union_list', arg_spaces('7,{"val":8}')]
2704+
args += [f'--{prefix}union_list', arg_spaces('{"val":9}'), f'--{prefix}union_list', '10']
26872705
cfg = Cfg(_cli_parse_args=args)
26882706
expected = {
26892707
'num_list': None,
@@ -2693,9 +2711,14 @@ def check_answer(cfg, prefix, expected):
26932711
}
26942712
check_answer(cfg, prefix, expected)
26952713

2696-
args = [f'--{prefix}str_list', '["0,0","1,1"]']
2697-
args += [f'--{prefix}str_list', '"2,2","3,3"']
2698-
args += [f'--{prefix}str_list', '"4,4"', f'--{prefix}str_list', '"5,5"']
2714+
args = [f'--{prefix}str_list', arg_spaces('["0,0","1,1"]', has_quote_comma=True)]
2715+
args += [f'--{prefix}str_list', arg_spaces('"2,2","3,3"', has_quote_comma=True)]
2716+
args += [
2717+
f'--{prefix}str_list',
2718+
arg_spaces('"4,4"', has_quote_comma=True),
2719+
f'--{prefix}str_list',
2720+
arg_spaces('"5,5"', has_quote_comma=True),
2721+
]
26992722
cfg = Cfg(_cli_parse_args=args)
27002723
expected = {
27012724
'num_list': None,
@@ -2706,29 +2729,31 @@ def check_answer(cfg, prefix, expected):
27062729
check_answer(cfg, prefix, expected)
27072730

27082731

2709-
def test_cli_list_json_value_parsing():
2732+
@pytest.mark.parametrize('arg_spaces', [no_add_cli_arg_spaces, add_cli_arg_spaces])
2733+
def test_cli_list_json_value_parsing(arg_spaces):
27102734
class Cfg(BaseSettings):
27112735
json_list: List[Union[str, bool, None]]
27122736

27132737
assert Cfg(
27142738
_cli_parse_args=[
27152739
'--json_list',
2716-
'true,"true"',
2740+
arg_spaces('true,"true"'),
27172741
'--json_list',
2718-
'false,"false"',
2742+
arg_spaces('false,"false"'),
27192743
'--json_list',
2720-
'null,"null"',
2744+
arg_spaces('null,"null"'),
27212745
'--json_list',
2722-
'hi,"bye"',
2746+
arg_spaces('hi,"bye"'),
27232747
]
27242748
).model_dump() == {'json_list': [True, 'true', False, 'false', None, 'null', 'hi', 'bye']}
27252749

27262750
assert Cfg(_cli_parse_args=['--json_list', '"","","",""']).model_dump() == {'json_list': ['', '', '', '']}
27272751
assert Cfg(_cli_parse_args=['--json_list', ',,,']).model_dump() == {'json_list': ['', '', '', '']}
27282752

27292753

2754+
@pytest.mark.parametrize('arg_spaces', [no_add_cli_arg_spaces, add_cli_arg_spaces])
27302755
@pytest.mark.parametrize('prefix', ['', 'child.'])
2731-
def test_cli_dict_arg(prefix):
2756+
def test_cli_dict_arg(prefix, arg_spaces):
27322757
class Child(BaseModel):
27332758
check_dict: Dict[str, str]
27342759

@@ -2737,19 +2762,34 @@ class Cfg(BaseSettings):
27372762
child: Optional[Child] = None
27382763

27392764
args: List[str] = []
2740-
args = [f'--{prefix}check_dict', '{"k1":"a","k2":"b"}']
2741-
args += [f'--{prefix}check_dict', '{"k3":"c"},{"k4":"d"}']
2742-
args += [f'--{prefix}check_dict', '{"k5":"e"}', f'--{prefix}check_dict', '{"k6":"f"}']
2743-
args += [f'--{prefix}check_dict', '[k7=g,k8=h]']
2744-
args += [f'--{prefix}check_dict', 'k9=i,k10=j']
2745-
args += [f'--{prefix}check_dict', 'k11=k', f'--{prefix}check_dict', 'k12=l']
2746-
args += [f'--{prefix}check_dict', '[{"k13":"m"},k14=n]', f'--{prefix}check_dict', '[k15=o,{"k16":"p"}]']
2747-
args += [f'--{prefix}check_dict', '{"k17":"q"},k18=r', f'--{prefix}check_dict', 'k19=s,{"k20":"t"}']
2748-
args += [f'--{prefix}check_dict', '{"k21":"u"},k22=v,{"k23":"w"}']
2749-
args += [f'--{prefix}check_dict', 'k24=x,{"k25":"y"},k26=z']
2750-
args += [f'--{prefix}check_dict', '[k27="x,y",k28="x,y"]']
2751-
args += [f'--{prefix}check_dict', 'k29="x,y",k30="x,y"']
2752-
args += [f'--{prefix}check_dict', 'k31="x,y"', f'--{prefix}check_dict', 'k32="x,y"']
2765+
args = [f'--{prefix}check_dict', arg_spaces('{"k1":"a","k2":"b"}')]
2766+
args += [f'--{prefix}check_dict', arg_spaces('{"k3":"c"},{"k4":"d"}')]
2767+
args += [f'--{prefix}check_dict', arg_spaces('{"k5":"e"}'), f'--{prefix}check_dict', arg_spaces('{"k6":"f"}')]
2768+
args += [f'--{prefix}check_dict', arg_spaces('[k7=g,k8=h]')]
2769+
args += [f'--{prefix}check_dict', arg_spaces('k9=i,k10=j')]
2770+
args += [f'--{prefix}check_dict', arg_spaces('k11=k'), f'--{prefix}check_dict', arg_spaces('k12=l')]
2771+
args += [
2772+
f'--{prefix}check_dict',
2773+
arg_spaces('[{"k13":"m"},k14=n]'),
2774+
f'--{prefix}check_dict',
2775+
arg_spaces('[k15=o,{"k16":"p"}]'),
2776+
]
2777+
args += [
2778+
f'--{prefix}check_dict',
2779+
arg_spaces('{"k17":"q"},k18=r'),
2780+
f'--{prefix}check_dict',
2781+
arg_spaces('k19=s,{"k20":"t"}'),
2782+
]
2783+
args += [f'--{prefix}check_dict', arg_spaces('{"k21":"u"},k22=v,{"k23":"w"}')]
2784+
args += [f'--{prefix}check_dict', arg_spaces('k24=x,{"k25":"y"},k26=z')]
2785+
args += [f'--{prefix}check_dict', arg_spaces('[k27="x,y",k28="x,y"]', has_quote_comma=True)]
2786+
args += [f'--{prefix}check_dict', arg_spaces('k29="x,y",k30="x,y"', has_quote_comma=True)]
2787+
args += [
2788+
f'--{prefix}check_dict',
2789+
arg_spaces('k31="x,y"', has_quote_comma=True),
2790+
f'--{prefix}check_dict',
2791+
arg_spaces('k32="x,y"', has_quote_comma=True),
2792+
]
27532793
cfg = Cfg(_cli_parse_args=args)
27542794
expected: Dict[str, Any] = {
27552795
'check_dict': {

0 commit comments

Comments
 (0)