Search code examples
pythonargparsepydantic

Argument parser from a Pydantic model


How do I create an argument parser (argparse.ArgumentParser) from a Pydantic model?

I have a Pydantic model:

from pydantic import BaseModel, Field

class MyItem(BaseModel):
    name: str
    age: int
    color: str = Field(default="red", description="Color of the item")

And I want to create an instance of MyItem using command line:

python myscript.py --name Jack --age 10 --color blue

This should yield to:

item = MyItem(name="Jack", age=10, color="blue")
... # Process the item

I would not like to hard-code the command-line arguments and I would like to create the command-line arguments dynamically from the Pydantic model.


Solution

  • I found an answer myself. Just:

    1. create an argument parser,
    2. turn the fields of the model as arguments of the parser,
    3. parse the command-line arguments,
    4. turn the arguments as dict and pass them to the model and
    5. process the instance of the model
    import argparse
    from pydantic import BaseModel, Field
    
    class MyItem(BaseModel):
        name: str
        age: int
        color: str = Field(default="red", description="Color of the item")
    
    def add_model(parser, model):
        "Add Pydantic model to an ArgumentParser"
        fields = model.__fields__
        for name, field in fields.items():
            parser.add_argument(
                f"--{name}", 
                dest=name, 
                type=field.type_, 
                default=field.default,
                help=field.field_info.description,
            )
    
    # 1. Create and parse command line arguments
    parser = argparse.ArgumentParser()
    
    # 2. Turn the fields of the model as arguments of the parser
    add_model(parser, MyItem)
    
    # 3. Parse the command-line arguments
    args = parser.parse_args()
    
    # 4. Turn the arguments as dict and pass them to the model
    item = MyItem(**vars(args))
    
    # 5. Do whatever
    print(repr(item))
    ...
    

    You may also add subparsers if you wish to add more functionality to the parser: https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_subparsers