@@ -473,13 +473,13 @@ models. There are two primary use cases for Pydantic settings CLI:
4734732 . When using Pydantic models to define CLIs.
474474
475475By default, the experience is tailored towards use case #1 and builds on the foundations established in [ parsing
476- environment variables] ( #parsing-environment-variables ) . If your use case primarily falls into #2 , you will likely want
477- to enable [ enforcing required arguments at the CLI] ( #enforce-required-arguments-at-cli ) .
476+ environment variables] ( #parsing-environment-variable-values ) . If your use case primarily falls into #2 , you will likely
477+ want to enable [ enforcing required arguments at the CLI] ( #enforce-required-arguments-at-cli ) .
478478
479479### The Basics
480480
481- To get started, let's revisit the example presented in [ parsing environment variables ] ( #parsing-environment-variables )
482- but using a Pydantic settings CLI:
481+ To get started, let's revisit the example presented in [ parsing environment
482+ variables ] ( #parsing-environment-variable-values ) but using a Pydantic settings CLI:
483483
484484``` py
485485import sys
@@ -528,16 +528,16 @@ print(Settings().model_dump())
528528To enable CLI parsing, we simply set the ` cli_parse_args ` flag to a valid value, which retains similar conotations as
529529defined in ` argparse ` . Alternatively, we can also directly provided the args to parse at time of instantiation:
530530
531- ``` py test="skip" lint="skip"
532- Settings(
533- _cli_parse_args = [
534- ' --v0=0 ' ,
535- ' --sub_model={"v1": "json-1", "v2": "json-2"} ' ,
536- ' --sub_model.v2=nested-2 ' ,
537- ' --sub_model.v3=3 ' ,
538- ' --sub_model.deep.v4=v4 ' ,
539- ]
540- )
531+ ``` py
532+ from pydantic_settings import BaseSettings
533+
534+
535+ class Settings ( BaseSettings ):
536+ this_foo: str
537+
538+
539+ print (Settings( _cli_parse_args = [ ' --this_foo ' , ' is such a foo ' ]).model_dump())
540+ # > {'this_foo': 'is such a foo'}
541541```
542542
543543Note that a CLI settings source is [ ** the topmost source** ] ( #field-value-priority ) by default unless its [ priority value
@@ -705,7 +705,7 @@ print(User().model_dump())
705705
706706Subcommands and positional arguments are expressed using the ` CliSubCommand ` and ` CliPositionalArg ` annotations. These
707707annotations can only be applied to required fields (i.e. fields that do not have a default value). Furthermore,
708- subcommands must be a valid type derived from the pydantic ` BaseModel ` class .
708+ subcommands must be a valid type derived from either a pydantic ` BaseModel ` or pydantic.dataclasses ` dataclass ` .
709709
710710!!! note
711711 CLI settings subcommands are limited to a single subparser per model. In other words, all subcommands for a model
@@ -720,6 +720,7 @@ subcommands must be a valid type derived from the pydantic `BaseModel` class.
720720import sys
721721
722722from pydantic import BaseModel, Field
723+ from pydantic.dataclasses import dataclass
723724
724725from pydantic_settings import (
725726 BaseSettings,
@@ -728,51 +729,45 @@ from pydantic_settings import (
728729)
729730
730731
731- class FooPlugin (BaseModel ):
732+ @dataclass
733+ class FooPlugin :
732734 """ git-plugins-foo - Extra deep foo plugin command"""
733735
734- my_feature: bool = Field(
735- default = False , description = ' Enable my feature on foo plugin'
736- )
736+ x_feature: bool = Field(default = False , description = ' Enable "X" feature' )
737737
738738
739- class BarPlugin (BaseModel ):
739+ @dataclass
740+ class BarPlugin :
740741 """ git-plugins-bar - Extra deep bar plugin command"""
741742
742- my_feature: bool = Field(
743- default = False , description = ' Enable my feature on bar plugin'
744- )
743+ y_feature: bool = Field(default = False , description = ' Enable "Y" feature' )
745744
746745
747- class Plugins (BaseModel ):
746+ @dataclass
747+ class Plugins :
748748 """ git-plugins - Fake plugins for GIT"""
749749
750750 foo: CliSubCommand[FooPlugin] = Field(description = ' Foo is fake plugin' )
751751
752- bar: CliSubCommand[BarPlugin] = Field(description = ' Bar is also a fake plugin' )
752+ bar: CliSubCommand[BarPlugin] = Field(description = ' Bar is fake plugin' )
753753
754754
755755class Clone (BaseModel ):
756756 """ git-clone - Clone a repository into a new directory"""
757757
758- repository: CliPositionalArg[str ] = Field(description = ' The repository to clone ' )
758+ repository: CliPositionalArg[str ] = Field(description = ' The repo ... ' )
759759
760- directory: CliPositionalArg[str ] = Field(description = ' The directory to clone into ' )
760+ directory: CliPositionalArg[str ] = Field(description = ' The dir ... ' )
761761
762- local: bool = Field(
763- default = False ,
764- description = ' When the resposity to clone from is on a local machine, bypass ...' ,
765- )
762+ local: bool = Field(default = False , description = ' When the repo ...' )
766763
767764
768765class Git (BaseSettings , cli_parse_args = True , cli_prog_name = ' git' ):
769766 """ git - The stupid content tracker"""
770767
771- clone: CliSubCommand[Clone] = Field(
772- description = ' Clone a repository into a new directory'
773- )
768+ clone: CliSubCommand[Clone] = Field(description = ' Clone a repo ...' )
774769
775- plugins: CliSubCommand[Plugins] = Field(description = ' Fake GIT plugin commands ' )
770+ plugins: CliSubCommand[Plugins] = Field(description = ' Fake GIT plugins ' )
776771
777772
778773try :
@@ -787,12 +782,12 @@ usage: git [-h] {clone,plugins} ...
787782git - The stupid content tracker
788783
789784options:
790- -h, --help show this help message and exit
785+ -h, --help show this help message and exit
791786
792787subcommands:
793788 {clone,plugins}
794- clone Clone a repository into a new directory
795- plugins Fake GIT plugin commands
789+ clone Clone a repo ...
790+ plugins Fake GIT plugins
796791"""
797792
798793
@@ -808,12 +803,12 @@ usage: git clone [-h] [--local bool] [--shared bool] REPOSITORY DIRECTORY
808803git-clone - Clone a repository into a new directory
809804
810805positional arguments:
811- REPOSITORY The repository to clone
812- DIRECTORY The directory to clone into
806+ REPOSITORY The repo ...
807+ DIRECTORY The dir ...
813808
814809options:
815- -h, --help show this help message and exit
816- --local bool When the resposity to clone from is on a local machine, bypass ... (default: False)
810+ -h, --help show this help message and exit
811+ --local bool When the repo ... (default: False)
817812"""
818813
819814
@@ -829,8 +824,8 @@ usage: git plugins bar [-h] [--my_feature bool]
829824git-plugins-bar - Extra deep bar plugin command
830825
831826options:
832- -h, --help show this help message and exit
833- --my_feature bool Enable my feature on bar plugin (default: False)
827+ -h, --help show this help message and exit
828+ --y_feature bool Enable "Y" feature (default: False)
834829"""
835830```
836831
@@ -843,7 +838,7 @@ The below flags can be used to customise the CLI experience to your needs.
843838Change the default program name displayed in the help text usage by setting ` cli_prog_name ` . By default, it will derive
844839the name of the currently executing program from ` sys.argv[0] ` , just like argparse.
845840
846- ``` py test="skip"
841+ ``` py
847842import sys
848843
849844from pydantic_settings import BaseSettings
@@ -853,8 +848,12 @@ class Settings(BaseSettings, cli_parse_args=True, cli_prog_name='appdantic'):
853848 pass
854849
855850
856- sys.argv = [' example.py' , ' --help' ]
857- Settings()
851+ try :
852+ sys.argv = [' example.py' , ' --help' ]
853+ Settings()
854+ except SystemExit as e:
855+ print (e)
856+ # > 0
858857"""
859858usage: appdantic [-h]
860859
@@ -870,7 +869,7 @@ is required is not strictly required from any single source (e.g. the CLI). Inst
870869sources provides the required value.
871870
872871However, if your use case [ aligns more with #2 ] ( #command-line-support ) , using Pydantic models to define CLIs, you will
873- likely want required fields to be _ strictly required at the CLI_ . We can enable this behavior by using the
872+ likely want required fields to be _ strictly required at the CLI_ . We can enable this behavior by using
874873` cli_enforce_required ` .
875874
876875``` py
@@ -902,7 +901,7 @@ example.py: error: the following arguments are required: --my_required_field
902901
903902#### Change the None Type Parse String
904903
905- Change the CLI string value that will be parsed (e.g. "null", "void", "None", etc.) into ` None ` type(None) by setting
904+ Change the CLI string value that will be parsed (e.g. "null", "void", "None", etc.) into ` None ` by setting
906905` cli_parse_none_str ` . By default it will use the ` env_parse_none_str ` value if set. Otherwise, it will default to "null"
907906if ` cli_avoid_json ` is ` False ` , and "None" if ` cli_avoid_json ` is ` True ` .
908907
@@ -928,7 +927,7 @@ print(Settings().model_dump())
928927
929928Hide ` None ` values from the CLI help text by enabling ` cli_hide_none_type ` .
930929
931- ``` py test="skip"
930+ ``` py
932931import sys
933932from typing import Optional
934933
@@ -941,8 +940,12 @@ class Settings(BaseSettings, cli_parse_args=True, cli_hide_none_type=True):
941940 v0: Optional[str ] = Field(description = ' the top level v0 option' )
942941
943942
944- sys.argv = [' example.py' , ' --help' ]
945- Settings()
943+ try :
944+ sys.argv = [' example.py' , ' --help' ]
945+ Settings()
946+ except SystemExit as e:
947+ print (e)
948+ # > 0
946949"""
947950usage: example.py [-h] [--v0 str]
948951
@@ -956,7 +959,7 @@ options:
956959
957960Avoid adding complex fields that result in JSON strings at the CLI by enabling ` cli_avoid_json ` .
958961
959- ``` py test="skip"
962+ ``` py
960963import sys
961964
962965from pydantic import BaseModel, Field
@@ -974,8 +977,12 @@ class Settings(BaseSettings, cli_parse_args=True, cli_avoid_json=True):
974977 )
975978
976979
977- sys.argv = [' example.py' , ' --help' ]
978- Settings()
980+ try :
981+ sys.argv = [' example.py' , ' --help' ]
982+ Settings()
983+ except SystemExit as e:
984+ print (e)
985+ # > 0
979986"""
980987usage: example.py [-h] [--sub_model.v1 int]
981988
@@ -998,7 +1005,7 @@ Alternatively, we can also configure CLI settings to pull from the class docstri
9981005 If the field is a union of nested models the group help text will always be pulled from the field description;
9991006 even if ` cli_use_class_docs_for_groups ` is set to ` True ` .
10001007
1001- ``` py test="skip"
1008+ ``` py
10021009import sys
10031010
10041011from pydantic import BaseModel, Field
@@ -1018,8 +1025,12 @@ class Settings(BaseSettings, cli_parse_args=True, cli_use_class_docs_for_groups=
10181025 sub_model: SubModel = Field(description = ' The help text from the field description' )
10191026
10201027
1021- sys.argv = [' example.py' , ' --help' ]
1022- Settings()
1028+ try :
1029+ sys.argv = [' example.py' , ' --help' ]
1030+ Settings()
1031+ except SystemExit as e:
1032+ print (e)
1033+ # > 0
10231034"""
10241035usage: example.py [-h] [--sub_model JSON] [--sub_model.v1 int]
10251036
@@ -1075,12 +1086,12 @@ command line arguments. The `CliSettingsSource` internal parser representation i
10751086therefore, requires parser methods that support the same attributes as their ` argparse ` counterparts. The available
10761087parser methods that can be customised, along with their argparse counterparts (the defaults), are listed below:
10771088
1078- * ` parse_args_method ` - argparse.ArgumentParser.parse_args
1079- * ` add_argument_method ` - argparse.ArgumentParser.add_argument
1080- * ` add_argument_group_method ` - argparse.ArgumentParser.add \_ argument_group
1081- * ` add_parser_method ` - argparse.\ _ SubParsersAction.add_parser
1082- * ` add_subparsers_method ` - argparse.ArgumentParser.add_subparsers
1083- * ` formatter_class ` - argparse.HelpFormatter
1089+ * ` parse_args_method ` - ( ` argparse.ArgumentParser.parse_args ` )
1090+ * ` add_argument_method ` - ( ` argparse.ArgumentParser.add_argument ` )
1091+ * ` add_argument_group_method ` - ( ` argparse.ArgumentParser.add_argument_group ` )
1092+ * ` add_parser_method ` - ( ` argparse._SubParsersAction.add_parser ` )
1093+ * ` add_subparsers_method ` - ( ` argparse.ArgumentParser.add_subparsers ` )
1094+ * ` formatter_class ` - ( ` argparse.HelpFormatter ` )
10841095
10851096For a non-argparse parser the parser methods can be set to ` None ` if not supported. The CLI settings will only raise an
10861097error when connecting to the root parser if a parser method is necessary but set to ` None ` .
0 commit comments