5353)
5454
5555ARGPARSE_OPTIONS_TEXT = 'options' if sys .version_info >= (3 , 10 ) else 'optional arguments'
56+ PYTHON_3_14 = sys .version_info >= (3 , 14 )
57+
58+
59+ def sanitize_cli_output (output : str ) -> str :
60+ output = re .sub (r'\bpython3? ' , '' , output )
61+ return output
5662
5763
5864@pytest .fixture (autouse = True )
@@ -247,7 +253,7 @@ class Cfg(BaseSettings):
247253 with pytest .raises (SystemExit ):
248254 CliApp .run (Cfg )
249255 assert (
250- capsys .readouterr ().out
256+ sanitize_cli_output ( capsys .readouterr ().out )
251257 == f"""usage: example.py [-h] {{sub-cmd}} ...
252258
253259{ ARGPARSE_OPTIONS_TEXT } :
@@ -263,7 +269,7 @@ class Cfg(BaseSettings):
263269 with pytest .raises (SystemExit ):
264270 CliApp .run (Cfg )
265271 assert (
266- capsys .readouterr ().out
272+ sanitize_cli_output ( capsys .readouterr ().out )
267273 == f"""usage: example.py sub-cmd [-h] POS-ARG
268274
269275positional arguments:
@@ -465,7 +471,7 @@ class Cfg(BaseSettings):
465471 CliApp .run (Cfg )
466472
467473 assert (
468- re .sub (r'0x\w+' , '0xffffffff' , capsys .readouterr ().out , flags = re .MULTILINE )
474+ re .sub (r'0x\w+' , '0xffffffff' , sanitize_cli_output ( capsys .readouterr ().out ) , flags = re .MULTILINE )
469475 == f"""usage: example.py [-h] [--foo str] [--bar int] [--boo int]
470476
471477{ ARGPARSE_OPTIONS_TEXT } :
@@ -495,7 +501,7 @@ class MultilineDoc(BaseSettings, cli_parse_args=True):
495501 Cfg ()
496502
497503 assert (
498- re .sub (r'0x\w+' , '0xffffffff' , capsys .readouterr ().out , flags = re .MULTILINE )
504+ re .sub (r'0x\w+' , '0xffffffff' , sanitize_cli_output ( capsys .readouterr ().out ) , flags = re .MULTILINE )
499505 == f"""usage: example.py [-h] [--date_str str]
500506
501507{ ARGPARSE_OPTIONS_TEXT } :
@@ -507,7 +513,7 @@ class MultilineDoc(BaseSettings, cli_parse_args=True):
507513 with pytest .raises (SystemExit ):
508514 MultilineDoc ()
509515 assert (
510- capsys .readouterr ().out
516+ sanitize_cli_output ( capsys .readouterr ().out )
511517 == f"""usage: example.py [-h]
512518
513519My
@@ -523,7 +529,7 @@ class MultilineDoc(BaseSettings, cli_parse_args=True):
523529 cli_settings_source = CliSettingsSource (MultilineDoc , formatter_class = argparse .HelpFormatter )
524530 MultilineDoc (_cli_settings_source = cli_settings_source (args = True ))
525531 assert (
526- capsys .readouterr ().out
532+ sanitize_cli_output ( capsys .readouterr ().out )
527533 == f"""usage: example.py [-h]
528534
529535My Multiline Doc
@@ -554,12 +560,19 @@ class Car(BaseSettings, cli_parse_args=True):
554560 with monkeypatch .context () as m :
555561 m .setattr (sys , 'argv' , ['example.py' , '--help' ])
556562
563+ if PYTHON_3_14 :
564+ text1 = ' [--driver.bark str] [--driver.caww str]\n [--driver.tweet str]'
565+ text2 = '\n '
566+ else :
567+ text1 = ' [--driver.bark str] [--driver.caww str] [--driver.tweet str]'
568+ text2 = ''
557569 with pytest .raises (SystemExit ):
558570 Car ()
571+ print (sanitize_cli_output (capsys .readouterr ().out ))
559572 assert (
560- capsys .readouterr ().out
573+ sanitize_cli_output ( capsys .readouterr ().out )
561574 == f"""usage: example.py [-h] [--driver [JSON]] [--driver.meow str]
562- [--driver.bark str] [--driver.caww str] [--driver.tweet str]
575+ { text1 }
563576
564577{ ARGPARSE_OPTIONS_TEXT } :
565578 -h, --help show this help message and exit
@@ -569,7 +582,7 @@ class Car(BaseSettings, cli_parse_args=True):
569582 --driver.meow str (default: purr)
570583 --driver.bark str (default: bark)
571584 --driver.caww str (default: caww)
572- --driver.tweet str (ifdef: required)
585+ --driver.tweet str (ifdef: required){ text2 }
573586"""
574587 )
575588
@@ -595,12 +608,21 @@ class Settings(BaseSettings, cli_parse_args=True):
595608 with monkeypatch .context () as m :
596609 m .setattr (sys , 'argv' , ['example.py' , '--help' ])
597610
598- with pytest .raises (SystemExit ):
599- Settings ()
600- assert (
601- capsys .readouterr ().out
602- == f"""usage: example.py [-h] [--flag bool] [--sub_model [JSON]]
603- [--sub_model.flag bool] [--sub_model.deep [JSON]]
611+ if PYTHON_3_14 :
612+ text = """ [--sub_model.flag bool] [--sub_model.deep [JSON]]
613+ [--sub_model.deep.flag bool]
614+ [--sub_model.deep.deeper [{JSON,null}]]
615+ [--sub_model.deep.deeper.flag bool]
616+ [--opt_model [{JSON,null}]] [--opt_model.flag bool]
617+ [--opt_model.deeper [{JSON,null}]]
618+ [--opt_model.deeper.flag bool] [--fact_model [JSON]]
619+ [--fact_model.flag bool] [--fact_model.deep [JSON]]
620+ [--fact_model.deep.flag bool]
621+ [--fact_model.deep.deeper [{JSON,null}]]
622+ [--fact_model.deep.deeper.flag bool]
623+ """
624+ else :
625+ text = """ [--sub_model.flag bool] [--sub_model.deep [JSON]]
604626 [--sub_model.deep.flag bool]
605627 [--sub_model.deep.deeper [{{JSON,null}}]]
606628 [--sub_model.deep.deeper.flag bool]
@@ -610,8 +632,13 @@ class Settings(BaseSettings, cli_parse_args=True):
610632 [--fact_model.flag bool] [--fact_model.deep [JSON]]
611633 [--fact_model.deep.flag bool]
612634 [--fact_model.deep.deeper [{{JSON,null}}]]
613- [--fact_model.deep.deeper.flag bool]
614-
635+ [--fact_model.deep.deeper.flag bool]"""
636+ with pytest .raises (SystemExit ):
637+ Settings ()
638+ assert (
639+ sanitize_cli_output (capsys .readouterr ().out )
640+ == f"""usage: example.py [-h] [--flag bool] [--sub_model [JSON]]
641+ { text }
615642{ ARGPARSE_OPTIONS_TEXT } :
616643 -h, --help show this help message and exit
617644 --flag bool (default: True)
@@ -1084,7 +1111,7 @@ class Root1(BaseSettings):
10841111 with pytest .raises (SystemExit ):
10851112 CliApp .run (Root1 )
10861113 assert (
1087- capsys .readouterr ().out
1114+ sanitize_cli_output ( capsys .readouterr ().out )
10881115 == f"""usage: example.py [-h] {{AlphaCmd,BetaCmd,GammaCmd}} ...
10891116
10901117Root Help
@@ -1105,7 +1132,7 @@ class Root1(BaseSettings):
11051132 with pytest .raises (SystemExit ):
11061133 Root1 (_cli_parse_args = True , _cli_use_class_docs_for_groups = True )
11071134 assert (
1108- capsys .readouterr ().out
1135+ sanitize_cli_output ( capsys .readouterr ().out )
11091136 == f"""usage: example.py [-h] {{AlphaCmd,BetaCmd,GammaCmd}} ...
11101137
11111138Root Help
@@ -1145,7 +1172,7 @@ class Root2(BaseSettings):
11451172 with pytest .raises (SystemExit ):
11461173 CliApp .run (Root2 , cli_args = True )
11471174 assert (
1148- capsys .readouterr ().out
1175+ sanitize_cli_output ( capsys .readouterr ().out )
11491176 == f"""usage: example.py [-h] {{AlphaCmd,GammaCmd,beta}} ...
11501177
11511178Root Help
@@ -1166,7 +1193,7 @@ class Root2(BaseSettings):
11661193 with pytest .raises (SystemExit ):
11671194 Root2 (_cli_parse_args = True , _cli_use_class_docs_for_groups = True )
11681195 assert (
1169- capsys .readouterr ().out
1196+ sanitize_cli_output ( capsys .readouterr ().out )
11701197 == f"""usage: example.py [-h] {{AlphaCmd,GammaCmd,beta}} ...
11711198
11721199Root Help
@@ -1206,7 +1233,7 @@ class Root3(BaseSettings):
12061233 with pytest .raises (SystemExit ):
12071234 CliApp .run (Root3 )
12081235 assert (
1209- capsys .readouterr ().out
1236+ sanitize_cli_output ( capsys .readouterr ().out )
12101237 == f"""usage: example.py [-h] {{beta,AlphaCmd,GammaCmd}} ...
12111238
12121239Root Help
@@ -1225,7 +1252,7 @@ class Root3(BaseSettings):
12251252 with pytest .raises (SystemExit ):
12261253 Root3 (_cli_parse_args = True , _cli_use_class_docs_for_groups = True )
12271254 assert (
1228- capsys .readouterr ().out
1255+ sanitize_cli_output ( capsys .readouterr ().out )
12291256 == f"""usage: example.py [-h] {{beta,AlphaCmd,GammaCmd}} ...
12301257
12311258Root Help
@@ -1419,12 +1446,16 @@ class Cfg(BaseSettings):
14191446 with monkeypatch .context () as m :
14201447 m .setattr (sys , 'argv' , ['example.py' , '--help' ])
14211448
1449+ if PYTHON_3_14 :
1450+ text = ' [--union_pet {{dog,cat,bird},int}]'
1451+ else :
1452+ text = ' [--union_pet {{dog,cat,bird},int}]'
14221453 with pytest .raises (SystemExit ):
14231454 CliApp .run (Cfg )
14241455 assert (
1425- capsys .readouterr ().out
1456+ sanitize_cli_output ( capsys .readouterr ().out )
14261457 == f"""usage: example.py [-h] [--pet {{dog,cat,bird}}]
1427- [--union_pet {{{{dog,cat,bird}},int}}]
1458+ { text }
14281459
14291460{ ARGPARSE_OPTIONS_TEXT } :
14301461 -h, --help show this help message and exit
@@ -1617,7 +1648,7 @@ class Settings(BaseSettings):
16171648 Settings (_cli_avoid_json = False )
16181649
16191650 assert (
1620- capsys .readouterr ().out
1651+ sanitize_cli_output ( capsys .readouterr ().out )
16211652 == f"""usage: example.py [-h] [--sub_model [JSON]] [--sub_model.v1 int]
16221653
16231654{ ARGPARSE_OPTIONS_TEXT } :
@@ -1633,7 +1664,7 @@ class Settings(BaseSettings):
16331664 Settings (_cli_avoid_json = True )
16341665
16351666 assert (
1636- capsys .readouterr ().out
1667+ sanitize_cli_output ( capsys .readouterr ().out )
16371668 == f"""usage: example.py [-h] [--sub_model.v1 int]
16381669
16391670{ ARGPARSE_OPTIONS_TEXT } :
@@ -1661,7 +1692,7 @@ class Settings(BaseSettings):
16611692 Settings (_cli_avoid_json = False )
16621693
16631694 assert (
1664- capsys .readouterr ().out
1695+ sanitize_cli_output ( capsys .readouterr ().out )
16651696 == f"""usage: example.py [-h] [--sub_model [JSON]]
16661697
16671698{ ARGPARSE_OPTIONS_TEXT } :
@@ -1676,7 +1707,7 @@ class Settings(BaseSettings):
16761707 Settings (_cli_avoid_json = True )
16771708
16781709 assert (
1679- capsys .readouterr ().out
1710+ sanitize_cli_output ( capsys .readouterr ().out )
16801711 == f"""usage: example.py [-h]
16811712
16821713{ ARGPARSE_OPTIONS_TEXT } :
@@ -1698,7 +1729,7 @@ class Settings(BaseSettings):
16981729 Settings (_cli_hide_none_type = False )
16991730
17001731 assert (
1701- capsys .readouterr ().out
1732+ sanitize_cli_output ( capsys .readouterr ().out )
17021733 == f"""usage: example.py [-h] [--v0 {{str,null}}]
17031734
17041735{ ARGPARSE_OPTIONS_TEXT } :
@@ -1711,7 +1742,7 @@ class Settings(BaseSettings):
17111742 Settings (_cli_hide_none_type = True )
17121743
17131744 assert (
1714- capsys .readouterr ().out
1745+ sanitize_cli_output ( capsys .readouterr ().out )
17151746 == f"""usage: example.py [-h] [--v0 str]
17161747
17171748{ ARGPARSE_OPTIONS_TEXT } :
@@ -1741,7 +1772,7 @@ class Settings(BaseSettings):
17411772 Settings (_cli_use_class_docs_for_groups = False )
17421773
17431774 assert (
1744- capsys .readouterr ().out
1775+ sanitize_cli_output ( capsys .readouterr ().out )
17451776 == f"""usage: example.py [-h] [--sub_model [JSON]] [--sub_model.v1 int]
17461777
17471778My application help text.
@@ -1761,7 +1792,7 @@ class Settings(BaseSettings):
17611792 Settings (_cli_use_class_docs_for_groups = True )
17621793
17631794 assert (
1764- capsys .readouterr ().out
1795+ sanitize_cli_output ( capsys .readouterr ().out )
17651796 == f"""usage: example.py [-h] [--sub_model [JSON]] [--sub_model.v1 int]
17661797
17671798My application help text.
@@ -1814,7 +1845,7 @@ class Settings(BaseSettings, cli_parse_args=True): ...
18141845 with pytest .raises (SystemExit ):
18151846 Settings ()
18161847 assert (
1817- capsys .readouterr ().err
1848+ sanitize_cli_output ( capsys .readouterr ().err )
18181849 == """usage: example.py [-h]
18191850example.py: error: unrecognized arguments: --bad-arg
18201851"""
@@ -2259,10 +2290,17 @@ class Settings(BaseSettings, cli_parse_args=True):
22592290 with pytest .raises (SystemExit ):
22602291 CliApp .run (Settings )
22612292
2293+ if PYTHON_3_14 :
2294+ text = """usage: python3 example.py [-h] [--visible_obj [JSON]]
2295+ [--visible_obj.visible_a int]
2296+ [--visible_obj.visible_b int]"""
2297+
2298+ else :
2299+ text = """usage: example.py [-h] [--visible_obj [JSON]] [--visible_obj.visible_a int]
2300+ [--visible_obj.visible_b int]"""
22622301 assert (
22632302 capsys .readouterr ().out
2264- == f"""usage: example.py [-h] [--visible_obj [JSON]] [--visible_obj.visible_a int]
2265- [--visible_obj.visible_b int]
2303+ == f"""{ text }
22662304
22672305{ ARGPARSE_OPTIONS_TEXT } :
22682306 -h, --help show this help message and exit
@@ -2313,18 +2351,24 @@ class Settings(BaseModel):
23132351 m .setattr (sys , 'argv' , ['example.py' , '--help' ])
23142352 with pytest .raises (SystemExit ):
23152353 CliApp .run (Settings )
2316- usage = (
2317- """usage: example.py [-h] [--circle-optional.radius float |
2354+ if PYTHON_3_14 :
2355+ usage = """usage: python3 example.py [-h] [--circle-optional.radius float |
2356+ --circle-optional.diameter float |
2357+ --circle-optional.perimeter float]
2358+ (--circle-required.radius float |
2359+ --circle-required.diameter float |
2360+ --circle-required.perimeter float)"""
2361+ elif sys .version_info >= (3 , 13 ):
2362+ usage = """usage: example.py [-h]
2363+ [--circle-optional.radius float | --circle-optional.diameter float | --circle-optional.perimeter float]
2364+ (--circle-required.radius float | --circle-required.diameter float | --circle-required.perimeter float)"""
2365+ else :
2366+ usage = """usage: example.py [-h] [--circle-optional.radius float |
23182367 --circle-optional.diameter float |
23192368 --circle-optional.perimeter float]
23202369 (--circle-required.radius float |
23212370 --circle-required.diameter float |
23222371 --circle-required.perimeter float)"""
2323- if sys .version_info >= (3 , 13 )
2324- else """usage: example.py [-h]
2325- [--circle-optional.radius float | --circle-optional.diameter float | --circle-optional.perimeter float]
2326- (--circle-required.radius float | --circle-required.diameter float | --circle-required.perimeter float)"""
2327- )
23282372 assert (
23292373 capsys .readouterr ().out
23302374 == f"""{ usage }
@@ -2523,7 +2567,7 @@ class Root(BaseModel):
25232567 with pytest .raises (SystemExit ):
25242568 CliApp .run (Root )
25252569 assert (
2526- capsys .readouterr ().out
2570+ sanitize_cli_output ( capsys .readouterr ().out )
25272571 == f"""usage: example.py [-h] --root-arg str {{root-subcmd,other-subcmd}} ...
25282572
25292573{ ARGPARSE_OPTIONS_TEXT } :
@@ -2537,13 +2581,18 @@ class Root(BaseModel):
25372581"""
25382582 )
25392583
2584+ if PYTHON_3_14 :
2585+ usage = """usage: python3 example.py root-subcmd [-h] --sub-arg str
2586+ {sub-subcmd,sub-other-subcmd} ..."""
2587+ else :
2588+ usage = """usage: example.py root-subcmd [-h] --sub-arg str
2589+ {{sub-subcmd,sub-other-subcmd}} ..."""
25402590 m .setattr (sys , 'argv' , ['example.py' , 'root-subcmd' , '--help' ])
25412591 with pytest .raises (SystemExit ):
25422592 CliApp .run (Root )
25432593 assert (
25442594 capsys .readouterr ().out
2545- == f"""usage: example.py root-subcmd [-h] --sub-arg str
2546- {{sub-subcmd,sub-other-subcmd}} ...
2595+ == f"""{ usage }
25472596
25482597{ ARGPARSE_OPTIONS_TEXT } :
25492598 -h, --help show this help message and exit
@@ -2556,12 +2605,17 @@ class Root(BaseModel):
25562605"""
25572606 )
25582607
2608+ if PYTHON_3_14 :
2609+ usage = """usage: python3 example.py root-subcmd sub-subcmd [-h] --deep-arg str
2610+ DEEP-POS-ARG"""
2611+ else :
2612+ usage = """usage: example.py root-subcmd sub-subcmd [-h] --deep-arg str DEEP-POS-ARG"""
25592613 m .setattr (sys , 'argv' , ['example.py' , 'root-subcmd' , 'sub-subcmd' , '--help' ])
25602614 with pytest .raises (SystemExit ):
25612615 CliApp .run (Root )
25622616 assert (
25632617 capsys .readouterr ().out
2564- == f"""usage: example.py root-subcmd sub-subcmd [-h] --deep-arg str DEEP-POS-ARG
2618+ == f"""{ usage }
25652619
25662620positional arguments:
25672621 DEEP-POS-ARG
0 commit comments