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+ output = output .replace ('python.exe -m pytest' , 'example.py' ) # For Windows compatibility
62+ return output
5663
5764
5865@pytest .fixture (autouse = True )
@@ -247,7 +254,7 @@ class Cfg(BaseSettings):
247254 with pytest .raises (SystemExit ):
248255 CliApp .run (Cfg )
249256 assert (
250- capsys .readouterr ().out
257+ sanitize_cli_output ( capsys .readouterr ().out )
251258 == f"""usage: example.py [-h] {{sub-cmd}} ...
252259
253260{ ARGPARSE_OPTIONS_TEXT } :
@@ -263,7 +270,7 @@ class Cfg(BaseSettings):
263270 with pytest .raises (SystemExit ):
264271 CliApp .run (Cfg )
265272 assert (
266- capsys .readouterr ().out
273+ sanitize_cli_output ( capsys .readouterr ().out )
267274 == f"""usage: example.py sub-cmd [-h] POS-ARG
268275
269276positional arguments:
@@ -465,7 +472,7 @@ class Cfg(BaseSettings):
465472 CliApp .run (Cfg )
466473
467474 assert (
468- re .sub (r'0x\w+' , '0xffffffff' , capsys .readouterr ().out , flags = re .MULTILINE )
475+ re .sub (r'0x\w+' , '0xffffffff' , sanitize_cli_output ( capsys .readouterr ().out ) , flags = re .MULTILINE )
469476 == f"""usage: example.py [-h] [--foo str] [--bar int] [--boo int]
470477
471478{ ARGPARSE_OPTIONS_TEXT } :
@@ -495,7 +502,7 @@ class MultilineDoc(BaseSettings, cli_parse_args=True):
495502 Cfg ()
496503
497504 assert (
498- re .sub (r'0x\w+' , '0xffffffff' , capsys .readouterr ().out , flags = re .MULTILINE )
505+ re .sub (r'0x\w+' , '0xffffffff' , sanitize_cli_output ( capsys .readouterr ().out ) , flags = re .MULTILINE )
499506 == f"""usage: example.py [-h] [--date_str str]
500507
501508{ ARGPARSE_OPTIONS_TEXT } :
@@ -507,7 +514,7 @@ class MultilineDoc(BaseSettings, cli_parse_args=True):
507514 with pytest .raises (SystemExit ):
508515 MultilineDoc ()
509516 assert (
510- capsys .readouterr ().out
517+ sanitize_cli_output ( capsys .readouterr ().out )
511518 == f"""usage: example.py [-h]
512519
513520My
@@ -523,7 +530,7 @@ class MultilineDoc(BaseSettings, cli_parse_args=True):
523530 cli_settings_source = CliSettingsSource (MultilineDoc , formatter_class = argparse .HelpFormatter )
524531 MultilineDoc (_cli_settings_source = cli_settings_source (args = True ))
525532 assert (
526- capsys .readouterr ().out
533+ sanitize_cli_output ( capsys .readouterr ().out )
527534 == f"""usage: example.py [-h]
528535
529536My Multiline Doc
@@ -554,12 +561,16 @@ class Car(BaseSettings, cli_parse_args=True):
554561 with monkeypatch .context () as m :
555562 m .setattr (sys , 'argv' , ['example.py' , '--help' ])
556563
564+ if PYTHON_3_14 :
565+ text1 = ' [--driver.bark str] [--driver.caww str]\n [--driver.tweet str]'
566+ else :
567+ text1 = ' [--driver.bark str] [--driver.caww str] [--driver.tweet str]'
557568 with pytest .raises (SystemExit ):
558569 Car ()
559570 assert (
560- capsys .readouterr ().out
571+ sanitize_cli_output ( capsys .readouterr ().out )
561572 == f"""usage: example.py [-h] [--driver [JSON]] [--driver.meow str]
562- [--driver.bark str] [--driver.caww str] [--driver.tweet str]
573+ { text1 }
563574
564575{ ARGPARSE_OPTIONS_TEXT } :
565576 -h, --help show this help message and exit
@@ -595,23 +606,38 @@ class Settings(BaseSettings, cli_parse_args=True):
595606 with monkeypatch .context () as m :
596607 m .setattr (sys , 'argv' , ['example.py' , '--help' ])
597608
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]]
609+ if PYTHON_3_14 :
610+ text = """ [--sub_model.flag bool] [--sub_model.deep [JSON]]
611+ [--sub_model.deep.flag bool]
612+ [--sub_model.deep.deeper [{JSON,null}]]
613+ [--sub_model.deep.deeper.flag bool]
614+ [--opt_model [{JSON,null}]] [--opt_model.flag bool]
615+ [--opt_model.deeper [{JSON,null}]]
616+ [--opt_model.deeper.flag bool] [--fact_model [JSON]]
617+ [--fact_model.flag bool] [--fact_model.deep [JSON]]
618+ [--fact_model.deep.flag bool]
619+ [--fact_model.deep.deeper [{JSON,null}]]
620+ [--fact_model.deep.deeper.flag bool]
621+ """
622+ else :
623+ text = """ [--sub_model.flag bool] [--sub_model.deep [JSON]]
604624 [--sub_model.deep.flag bool]
605- [--sub_model.deep.deeper [{{ JSON,null} }]]
625+ [--sub_model.deep.deeper [{JSON,null}]]
606626 [--sub_model.deep.deeper.flag bool]
607- [--opt_model [{{ JSON,null} }]] [--opt_model.flag bool]
608- [--opt_model.deeper [{{ JSON,null} }]]
627+ [--opt_model [{JSON,null}]] [--opt_model.flag bool]
628+ [--opt_model.deeper [{JSON,null}]]
609629 [--opt_model.deeper.flag bool] [--fact_model [JSON]]
610630 [--fact_model.flag bool] [--fact_model.deep [JSON]]
611631 [--fact_model.deep.flag bool]
612- [--fact_model.deep.deeper [{{ JSON,null} }]]
632+ [--fact_model.deep.deeper [{JSON,null}]]
613633 [--fact_model.deep.deeper.flag bool]
614-
634+ """
635+ with pytest .raises (SystemExit ):
636+ Settings ()
637+ assert (
638+ sanitize_cli_output (capsys .readouterr ().out )
639+ == f"""usage: example.py [-h] [--flag bool] [--sub_model [JSON]]
640+ { text }
615641{ ARGPARSE_OPTIONS_TEXT } :
616642 -h, --help show this help message and exit
617643 --flag bool (default: True)
@@ -1084,7 +1110,7 @@ class Root1(BaseSettings):
10841110 with pytest .raises (SystemExit ):
10851111 CliApp .run (Root1 )
10861112 assert (
1087- capsys .readouterr ().out
1113+ sanitize_cli_output ( capsys .readouterr ().out )
10881114 == f"""usage: example.py [-h] {{AlphaCmd,BetaCmd,GammaCmd}} ...
10891115
10901116Root Help
@@ -1105,7 +1131,7 @@ class Root1(BaseSettings):
11051131 with pytest .raises (SystemExit ):
11061132 Root1 (_cli_parse_args = True , _cli_use_class_docs_for_groups = True )
11071133 assert (
1108- capsys .readouterr ().out
1134+ sanitize_cli_output ( capsys .readouterr ().out )
11091135 == f"""usage: example.py [-h] {{AlphaCmd,BetaCmd,GammaCmd}} ...
11101136
11111137Root Help
@@ -1145,7 +1171,7 @@ class Root2(BaseSettings):
11451171 with pytest .raises (SystemExit ):
11461172 CliApp .run (Root2 , cli_args = True )
11471173 assert (
1148- capsys .readouterr ().out
1174+ sanitize_cli_output ( capsys .readouterr ().out )
11491175 == f"""usage: example.py [-h] {{AlphaCmd,GammaCmd,beta}} ...
11501176
11511177Root Help
@@ -1166,7 +1192,7 @@ class Root2(BaseSettings):
11661192 with pytest .raises (SystemExit ):
11671193 Root2 (_cli_parse_args = True , _cli_use_class_docs_for_groups = True )
11681194 assert (
1169- capsys .readouterr ().out
1195+ sanitize_cli_output ( capsys .readouterr ().out )
11701196 == f"""usage: example.py [-h] {{AlphaCmd,GammaCmd,beta}} ...
11711197
11721198Root Help
@@ -1206,7 +1232,7 @@ class Root3(BaseSettings):
12061232 with pytest .raises (SystemExit ):
12071233 CliApp .run (Root3 )
12081234 assert (
1209- capsys .readouterr ().out
1235+ sanitize_cli_output ( capsys .readouterr ().out )
12101236 == f"""usage: example.py [-h] {{beta,AlphaCmd,GammaCmd}} ...
12111237
12121238Root Help
@@ -1225,7 +1251,7 @@ class Root3(BaseSettings):
12251251 with pytest .raises (SystemExit ):
12261252 Root3 (_cli_parse_args = True , _cli_use_class_docs_for_groups = True )
12271253 assert (
1228- capsys .readouterr ().out
1254+ sanitize_cli_output ( capsys .readouterr ().out )
12291255 == f"""usage: example.py [-h] {{beta,AlphaCmd,GammaCmd}} ...
12301256
12311257Root Help
@@ -1419,12 +1445,16 @@ class Cfg(BaseSettings):
14191445 with monkeypatch .context () as m :
14201446 m .setattr (sys , 'argv' , ['example.py' , '--help' ])
14211447
1448+ if PYTHON_3_14 :
1449+ text = ' [--union_pet {{dog,cat,bird},int}]'
1450+ else :
1451+ text = ' [--union_pet {{dog,cat,bird},int}]'
14221452 with pytest .raises (SystemExit ):
14231453 CliApp .run (Cfg )
14241454 assert (
1425- capsys .readouterr ().out
1455+ sanitize_cli_output ( capsys .readouterr ().out )
14261456 == f"""usage: example.py [-h] [--pet {{dog,cat,bird}}]
1427- [--union_pet {{{{dog,cat,bird}},int}}]
1457+ { text }
14281458
14291459{ ARGPARSE_OPTIONS_TEXT } :
14301460 -h, --help show this help message and exit
@@ -1617,7 +1647,7 @@ class Settings(BaseSettings):
16171647 Settings (_cli_avoid_json = False )
16181648
16191649 assert (
1620- capsys .readouterr ().out
1650+ sanitize_cli_output ( capsys .readouterr ().out )
16211651 == f"""usage: example.py [-h] [--sub_model [JSON]] [--sub_model.v1 int]
16221652
16231653{ ARGPARSE_OPTIONS_TEXT } :
@@ -1633,7 +1663,7 @@ class Settings(BaseSettings):
16331663 Settings (_cli_avoid_json = True )
16341664
16351665 assert (
1636- capsys .readouterr ().out
1666+ sanitize_cli_output ( capsys .readouterr ().out )
16371667 == f"""usage: example.py [-h] [--sub_model.v1 int]
16381668
16391669{ ARGPARSE_OPTIONS_TEXT } :
@@ -1661,7 +1691,7 @@ class Settings(BaseSettings):
16611691 Settings (_cli_avoid_json = False )
16621692
16631693 assert (
1664- capsys .readouterr ().out
1694+ sanitize_cli_output ( capsys .readouterr ().out )
16651695 == f"""usage: example.py [-h] [--sub_model [JSON]]
16661696
16671697{ ARGPARSE_OPTIONS_TEXT } :
@@ -1676,7 +1706,7 @@ class Settings(BaseSettings):
16761706 Settings (_cli_avoid_json = True )
16771707
16781708 assert (
1679- capsys .readouterr ().out
1709+ sanitize_cli_output ( capsys .readouterr ().out )
16801710 == f"""usage: example.py [-h]
16811711
16821712{ ARGPARSE_OPTIONS_TEXT } :
@@ -1698,7 +1728,7 @@ class Settings(BaseSettings):
16981728 Settings (_cli_hide_none_type = False )
16991729
17001730 assert (
1701- capsys .readouterr ().out
1731+ sanitize_cli_output ( capsys .readouterr ().out )
17021732 == f"""usage: example.py [-h] [--v0 {{str,null}}]
17031733
17041734{ ARGPARSE_OPTIONS_TEXT } :
@@ -1711,7 +1741,7 @@ class Settings(BaseSettings):
17111741 Settings (_cli_hide_none_type = True )
17121742
17131743 assert (
1714- capsys .readouterr ().out
1744+ sanitize_cli_output ( capsys .readouterr ().out )
17151745 == f"""usage: example.py [-h] [--v0 str]
17161746
17171747{ ARGPARSE_OPTIONS_TEXT } :
@@ -1741,7 +1771,7 @@ class Settings(BaseSettings):
17411771 Settings (_cli_use_class_docs_for_groups = False )
17421772
17431773 assert (
1744- capsys .readouterr ().out
1774+ sanitize_cli_output ( capsys .readouterr ().out )
17451775 == f"""usage: example.py [-h] [--sub_model [JSON]] [--sub_model.v1 int]
17461776
17471777My application help text.
@@ -1761,7 +1791,7 @@ class Settings(BaseSettings):
17611791 Settings (_cli_use_class_docs_for_groups = True )
17621792
17631793 assert (
1764- capsys .readouterr ().out
1794+ sanitize_cli_output ( capsys .readouterr ().out )
17651795 == f"""usage: example.py [-h] [--sub_model [JSON]] [--sub_model.v1 int]
17661796
17671797My application help text.
@@ -1814,7 +1844,7 @@ class Settings(BaseSettings, cli_parse_args=True): ...
18141844 with pytest .raises (SystemExit ):
18151845 Settings ()
18161846 assert (
1817- capsys .readouterr ().err
1847+ sanitize_cli_output ( capsys .readouterr ().err )
18181848 == """usage: example.py [-h]
18191849example.py: error: unrecognized arguments: --bad-arg
18201850"""
@@ -2259,10 +2289,17 @@ class Settings(BaseSettings, cli_parse_args=True):
22592289 with pytest .raises (SystemExit ):
22602290 CliApp .run (Settings )
22612291
2292+ if PYTHON_3_14 :
2293+ text = """usage: example.py [-h] [--visible_obj [JSON]]
2294+ [--visible_obj.visible_a int]
2295+ [--visible_obj.visible_b int]"""
2296+
2297+ else :
2298+ text = """usage: example.py [-h] [--visible_obj [JSON]] [--visible_obj.visible_a int]
2299+ [--visible_obj.visible_b int]"""
22622300 assert (
2263- capsys .readouterr ().out
2264- == f"""usage: example.py [-h] [--visible_obj [JSON]] [--visible_obj.visible_a int]
2265- [--visible_obj.visible_b int]
2301+ sanitize_cli_output (capsys .readouterr ().out )
2302+ == f"""{ text }
22662303
22672304{ ARGPARSE_OPTIONS_TEXT } :
22682305 -h, --help show this help message and exit
@@ -2313,20 +2350,26 @@ class Settings(BaseModel):
23132350 m .setattr (sys , 'argv' , ['example.py' , '--help' ])
23142351 with pytest .raises (SystemExit ):
23152352 CliApp .run (Settings )
2316- usage = (
2317- """usage: example.py [-h] [--circle-optional.radius float |
2353+ if PYTHON_3_14 :
2354+ usage = """usage: example.py [-h] [--circle-optional.radius float |
2355+ --circle-optional.diameter float |
2356+ --circle-optional.perimeter float]
2357+ (--circle-required.radius float |
2358+ --circle-required.diameter float |
2359+ --circle-required.perimeter float)"""
2360+ elif sys .version_info >= (3 , 13 ):
2361+ usage = """usage: example.py [-h] [--circle-optional.radius float |
23182362 --circle-optional.diameter float |
23192363 --circle-optional.perimeter float]
23202364 (--circle-required.radius float |
23212365 --circle-required.diameter float |
23222366 --circle-required.perimeter float)"""
2323- if sys . version_info >= ( 3 , 13 )
2324- else """usage: example.py [-h]
2367+ else :
2368+ usage = """usage: example.py [-h]
23252369 [--circle-optional.radius float | --circle-optional.diameter float | --circle-optional.perimeter float]
23262370 (--circle-required.radius float | --circle-required.diameter float | --circle-required.perimeter float)"""
2327- )
23282371 assert (
2329- capsys .readouterr ().out
2372+ sanitize_cli_output ( capsys .readouterr ().out )
23302373 == f"""{ usage }
23312374
23322375{ ARGPARSE_OPTIONS_TEXT } :
@@ -2523,7 +2566,7 @@ class Root(BaseModel):
25232566 with pytest .raises (SystemExit ):
25242567 CliApp .run (Root )
25252568 assert (
2526- capsys .readouterr ().out
2569+ sanitize_cli_output ( capsys .readouterr ().out )
25272570 == f"""usage: example.py [-h] --root-arg str {{root-subcmd,other-subcmd}} ...
25282571
25292572{ ARGPARSE_OPTIONS_TEXT } :
@@ -2537,13 +2580,18 @@ class Root(BaseModel):
25372580"""
25382581 )
25392582
2583+ if PYTHON_3_14 :
2584+ usage = """usage: example.py root-subcmd [-h] --sub-arg str
2585+ {sub-subcmd,sub-other-subcmd} ..."""
2586+ else :
2587+ usage = """usage: example.py root-subcmd [-h] --sub-arg str
2588+ {sub-subcmd,sub-other-subcmd} ..."""
25402589 m .setattr (sys , 'argv' , ['example.py' , 'root-subcmd' , '--help' ])
25412590 with pytest .raises (SystemExit ):
25422591 CliApp .run (Root )
25432592 assert (
2544- capsys .readouterr ().out
2545- == f"""usage: example.py root-subcmd [-h] --sub-arg str
2546- {{sub-subcmd,sub-other-subcmd}} ...
2593+ sanitize_cli_output (capsys .readouterr ().out )
2594+ == f"""{ usage }
25472595
25482596{ ARGPARSE_OPTIONS_TEXT } :
25492597 -h, --help show this help message and exit
@@ -2556,12 +2604,17 @@ class Root(BaseModel):
25562604"""
25572605 )
25582606
2607+ if PYTHON_3_14 :
2608+ usage = """usage: example.py root-subcmd sub-subcmd [-h] --deep-arg str
2609+ DEEP-POS-ARG"""
2610+ else :
2611+ usage = """usage: example.py root-subcmd sub-subcmd [-h] --deep-arg str DEEP-POS-ARG"""
25592612 m .setattr (sys , 'argv' , ['example.py' , 'root-subcmd' , 'sub-subcmd' , '--help' ])
25602613 with pytest .raises (SystemExit ):
25612614 CliApp .run (Root )
25622615 assert (
2563- capsys .readouterr ().out
2564- == f"""usage: example.py root-subcmd sub-subcmd [-h] --deep-arg str DEEP-POS-ARG
2616+ sanitize_cli_output ( capsys .readouterr ().out )
2617+ == f"""{ usage }
25652618
25662619positional arguments:
25672620 DEEP-POS-ARG
0 commit comments