8

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.

miksus
  • 2,426
  • 1
  • 18
  • 34

1 Answers1

9

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

miksus
  • 2,426
  • 1
  • 18
  • 34