Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 969
miksus Avatar asked Mar 28 '26 02:03

miksus


2 Answers

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

like image 129
miksus Avatar answered Mar 31 '26 03:03

miksus


There is a library called pydantic-argparse, that might just do what you need, without additional boilerplate code.

Here is an example from its docs

import pydantic
import pydantic_argparse


class Arguments(pydantic.BaseModel):
    # Required Args
    string: str = pydantic.Field(description="a required string")
    integer: int = pydantic.Field(description="a required integer")
    flag: bool = pydantic.Field(description="a required flag")

    # Optional Args
    second_flag: bool = pydantic.Field(False, description="an optional flag")
    third_flag: bool = pydantic.Field(True, description="an optional flag")


def main() -> None:
    # Create Parser and Parse Args
    parser = pydantic_argparse.ArgumentParser(
        model=Arguments,
        prog="Example Program",
        description="Example Description",
        version="0.0.1",
        epilog="Example Epilog",
    )
    args = parser.parse_typed_args()

    # Print Args
    print(args)


if __name__ == "__main__":
    main()

like image 23
Krishna Avatar answered Mar 31 '26 04:03

Krishna



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!