Typed Argument Parsing with Pydantic enhanced version
Project description
Requirements
Requires Python 3.10+, and is compatible with the Pydantic library. Use Rich for better console output.
Installation
Installation with pip is simple:
$ pip install argparse-dantic
Example
from argparse_dantic import ArgumentParser, BaseModel, ArgumentField
class Arguments(BaseModel):
"""Simple Command-Line Arguments."""
# Required Args
string: str = ArgumentField("-s", description="a required string")
integer: int = ArgumentField("-i", description="a required integer")
flag: bool = ArgumentField("-f", description="a required flag")
# Optional Args
second_flag: bool = ArgumentField("-sec", default=False, description="an optional flag")
third_flag: bool = ArgumentField("-thi", default=True, description="an optional flag")
def main() -> None:
"""Simple Main Function."""
# Create Parser and Parse Args
parser = ArgumentParser(
model_class=Arguments,
prog="Example Program",
description="Example Description",
version="0.0.1",
epilog="Example Epilog",
)
args = ["-h"]
arguments = parser.parse_typed_args(args)
# Print Args
print(arguments)
if __name__ == "__main__":
main()
$ python3 example.py --help
Example Description
Usage: Example Program [-h] [-v] [--s STRING] [--i INTEGER] [--f] [--sec] [--no-thi]
Optional Arguments:
-s, --string STRING a required string (default: None)
-i, --integer INTEGER
a required integer (default: None)
-f, --flag a required flag (default: None)
-sec, --second-flag an optional flag (default: False)
-no-thi, --no-third-flag
an optional flag (default: True)
Help:
-h, --help show this help message and exit
-v, --version show program's version number and exit
Example Epilog
$ python3 example.py --string hello -i 42 -f
string='hello' integer=42 flag=True second_flag=False third_flag=True
Advanced Example
from typing import Annotated, Any, TypedDict, Literal
from argparse_dantic import (
BaseModel, ArgumentParser, CommandNameBind,
ArgumentField, CommandField, ModelField,
create_group
)
type LogLevels = Literal["debug", "info", "warning", "error", "critical"]
class GlobalData(TypedDict):
verbose: bool
quiet: bool
logging: "LoggingModel"
MGroup = create_group("Mutually Exclusive Group", "Mutually Exclusive Group Description").\
create_mutually_exclusive_group(required=False)
class MutuallyGroup(BaseModel, group=MGroup):
verbose: Annotated[bool, ArgumentField(default=False, description="Verbose Mode")]
quiet: Annotated[bool, ArgumentField(default=False, description="Quiet Mode")]
class LoggingModel(BaseModel):
level: Annotated[LogLevels, ArgumentField("l", default="info", description="Logging Level", env="ARGPARSE_DANTIC_TEST_LOG_LEVEL")]
file: Annotated[str, ArgumentField("f", default="app.log", description="Log File", env="ARGPARSE_DANTIC_TEST_LOG_FILE")]
class GlobalModel(MutuallyGroup):
global_data: GlobalData
logging: Annotated[LoggingModel, ModelField(connect_char=".")]
class BaseCommandModel(GlobalModel):
command_name: CommandNameBind
class BuildCommand(GlobalModel):
name: Annotated[str, ArgumentField(description="Project Name")]
version: Annotated[str, ArgumentField(description="Project Version")]
class ListToolsCommand(GlobalModel):
...
class ListInstallCommand(GlobalModel):
...
class ListCommand(BaseCommandModel):
tools: Annotated[ListToolsCommand, CommandField(description="List Tools Command")]
install: Annotated[ListInstallCommand, CommandField(description="List Install Command")]
class MainModel(BaseCommandModel):
build: Annotated[BuildCommand, CommandField(aliases=["bd"], description="Build Command")]
list: Annotated[ListCommand, CommandField(aliases=["ls"], description="Check Command")]
class Commands:
def __init__(self):
self.commands = {}
def register(self, name = None, parent = None):
def decorator(func):
nonlocal name
if name is None:
name = func.__name__
if parent is not None:
name = f"{parent}.{name}"
self.commands[name] = func
return func
return decorator
def __call__(self, name, parent = None) -> Any:
if parent:
name = f"{parent}.{name}"
return self.commands[name]
commands = Commands()
@commands.register()
def build(arguments: BuildCommand):
print(f"Building {arguments.name} version {arguments.version}")
@commands.register(name="list")
def list_(arguments: ListCommand):
commands(arguments.command_name, "list")(getattr(arguments, arguments.command_name))
@commands.register(parent="list")
def tools(arguments: ListToolsCommand):
print("List of tools")
@commands.register(parent="list")
def install(arguments: ListInstallCommand):
print("List of installed binaries")
if __name__ == "__main__":
parser = ArgumentParser(
model_class=MainModel,
prog="Advanced Example",
description="Advanced Example Description",
version="1.0.0"
)
args = ["build", "--name", "MyProject", "--logging.level", "error", "--quiet"]
arguments = parser.parse_typed_args(args)
parser.console.print("Global Data:")
parser.console.print("\tverbose:", arguments.global_data["verbose"])
parser.console.print("\tquiet:", arguments.global_data["quiet"])
parser.console.print("Logging Config:")
parser.console.print("\tlevel:", arguments.global_data["logging"].level)
parser.console.print("\tfile:", arguments.global_data["logging"].file)
try:
commands(arguments.command_name)(getattr(arguments, arguments.command_name))
except KeyError:
if arguments.command_name is None:
parser.console.print("No command specified")
else:
parser.console.print(f"Command {arguments.command_name} not found")
License
This project is licensed under the terms of the MIT license.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
argparse_dantic-0.2.2.tar.gz
(66.7 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file argparse_dantic-0.2.2.tar.gz.
File metadata
- Download URL: argparse_dantic-0.2.2.tar.gz
- Upload date:
- Size: 66.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5892e5e51ae75ce38844208e07634be2c68507a6a3277b717d070661219dcbf9
|
|
| MD5 |
68df7bf7800d6785788bfc932200c94d
|
|
| BLAKE2b-256 |
ebec1a27e1fe869d33fe90a78ca578747530a918731e0576a813867df5b3a32d
|
File details
Details for the file argparse_dantic-0.2.2-py3-none-any.whl.
File metadata
- Download URL: argparse_dantic-0.2.2-py3-none-any.whl
- Upload date:
- Size: 74.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12d2fd186e1168465df693a07312b6dc0eb83d5cbe05f1180876afbace916f46
|
|
| MD5 |
1db5ce6c7075e73a2613662fc8ca3d9b
|
|
| BLAKE2b-256 |
082cf34d3203903a3660e7de17e854842d2135600205af5bbf901e0d439bae30
|