Arguments¶
This guide covers all ways to define and configure arguments in argclass.
Basic Arguments¶
The simplest way to define an argument is with a type annotation. Arguments without defaults are required; arguments with defaults are optional. The type hint determines how string values from the command line are converted.
import argclass
class Parser(argclass.Parser):
name: str # Required string
count: int = 10 # Optional integer with default
ratio: float = 0.5 # Optional float with default
parser = Parser()
parser.parse_args(["--name", "test", "--count", "5"])
assert parser.name == "test"
assert parser.count == 5
assert parser.ratio == 0.5
Type Annotations¶
Supported Types¶
argclass automatically handles these types:
Type |
Description |
Example |
|---|---|---|
|
String value |
|
|
Integer value |
|
|
Floating point |
|
|
Boolean flag |
|
|
File path |
|
|
List of values |
|
|
Unique values |
|
|
Immutable set |
|
Optional Types¶
Use Optional[T] or T | None for arguments that may not be provided.
Unlike required arguments, these default to None when not specified,
allowing you to detect whether the user provided a value.
import argclass
from typing import Optional
class Parser(argclass.Parser):
required_arg: str
optional_arg: Optional[str]
optional_with_default: Optional[int] = 42
parser = Parser()
parser.parse_args(["--required-arg", "value"])
assert parser.required_arg == "value"
assert parser.optional_arg is None
assert parser.optional_with_default == 42
Collection Types¶
Collection types accept multiple values after the flag. Use list[T] to
preserve order and duplicates, set[T] for unique values, or frozenset[T]
for immutable unique values. argclass automatically configures nargs.
import argclass
class Parser(argclass.Parser):
files: list[str]
numbers: set[int]
tags: frozenset[str]
parser = Parser()
parser.parse_args([
"--files", "a.txt", "b.txt",
"--numbers", "1", "2", "2", "3",
"--tags", "web", "api", "web"
])
assert parser.files == ["a.txt", "b.txt"]
assert parser.numbers == {1, 2, 3}
assert parser.tags == frozenset(["web", "api"])
Literal Types¶
Use Literal[...] to restrict an argument to specific values. This is a
type-safe alternative to choices - the allowed values are defined in the
type annotation itself, making them visible to static type checkers.
import argclass
from typing import Literal
class Parser(argclass.Parser):
mode: Literal["ro", "rw"] = "ro"
level: Literal[1, 2, 3] = 1
parser = Parser()
parser.parse_args(["--mode", "rw", "--level", "2"])
assert parser.mode == "rw"
assert parser.level == 2
Literal types work with Optional for arguments that may not be provided:
import argclass
from typing import Literal, Optional
class Parser(argclass.Parser):
env: Optional[Literal["dev", "staging", "prod"]]
parser = Parser()
parser.parse_args([])
assert parser.env is None
parser.parse_args(["--env", "prod"])
assert parser.env == "prod"
You can also use Literal types in argument groups:
import argclass
from typing import Literal
class StorageGroup(argclass.Group):
type: Literal["s3", "posix"]
path: str = "/data"
class Parser(argclass.Parser):
storage = StorageGroup()
parser = Parser()
parser.parse_args(["--storage-type", "s3"])
assert parser.storage.type == "s3"
assert parser.storage.path == "/data"
Using Argument()¶
Use argclass.Argument() when you need more control: short aliases like -n,
help text for --help output, custom metavars, or other argparse options.
The first positional arguments define flag names.
import argclass
class Parser(argclass.Parser):
name: str = argclass.Argument(
"-n", "--name",
help="User name",
metavar="NAME",
)
count: int = argclass.Argument(default=1)
parser = Parser()
parser.parse_args(["-n", "Alice", "--count", "5"])
assert parser.name == "Alice"
assert parser.count == 5
Typed Argument Functions¶
For better IDE support and type checking, use the typed variants. These provide exact return type information to static analyzers like mypy and enable precise autocompletion in your editor.
ArgumentSingle¶
Use ArgumentSingle for arguments that accept exactly one value. Specify
the type parameter explicitly for proper type inference in your IDE.
import argclass
class Parser(argclass.Parser):
count: int = argclass.ArgumentSingle(type=int, default=10)
name: str = argclass.ArgumentSingle(type=str)
parser = Parser()
parser.parse_args(["--name", "test", "--count", "42"])
assert parser.count == 42
assert parser.name == "test"
ArgumentSequence¶
Use ArgumentSequence for arguments that accept multiple values. The result
is always a list. Use nargs="*" for zero-or-more, nargs="+" for one-or-more.
import argclass
class Parser(argclass.Parser):
numbers: list[int] = argclass.ArgumentSequence(type=int)
files: list[str] = argclass.ArgumentSequence(type=str, nargs="*", default=[])
parser = Parser()
parser.parse_args(["--numbers", "1", "2", "3"])
assert parser.numbers == [1, 2, 3]
assert parser.files == []
Boolean Flags¶
Boolean arguments have special handling in argclass.
Shortcut syntax - Using bool = False or bool = True directly:
import argclass
class Parser(argclass.Parser):
# bool = False is a shortcut for action="store_true"
# The flag --debug sets it to True
debug: bool = False
# bool = True is a shortcut for action="store_false"
# The flag --no-cache sets it to False
cache: bool = True
parser = Parser()
parser.parse_args(["--debug", "--cache"])
assert parser.debug is True
assert parser.cache is False
Explicit syntax - When using argclass.Argument() for booleans (e.g., to add
help text or aliases), you must explicitly specify the action parameter:
import argclass
class Parser(argclass.Parser):
# Using Argument() requires explicit action
verbose: bool = argclass.Argument(
"-v", "--verbose",
action=argclass.Actions.STORE_TRUE, # Required!
default=False,
help="Enable verbose output"
)
# Can also use string literal
quiet: bool = argclass.Argument(
"-q", "--quiet",
action="store_true", # String literal works too
default=False,
help="Suppress output"
)
parser = Parser()
parser.parse_args(["-v", "-q"])
assert parser.verbose is True
assert parser.quiet is True
Without action, the boolean argument expects a value like --verbose true.
Actions¶
Actions define how argument values are stored. Use STORE_TRUE for flags
that enable features, STORE_FALSE for flags that disable features, and
COUNT for arguments that can be repeated (like -vvv for verbosity).
import argclass
class Parser(argclass.Parser):
verbose: bool = argclass.Argument(
"-v",
action=argclass.Actions.STORE_TRUE,
default=False
)
no_cache: bool = argclass.Argument(
action=argclass.Actions.STORE_FALSE,
default=True
)
verbosity: int = argclass.Argument(
action=argclass.Actions.COUNT,
default=0
)
parser = Parser()
parser.parse_args(["-v", "--no-cache", "--verbosity", "--verbosity"])
assert parser.verbose is True
assert parser.no_cache is False
assert parser.verbosity == 2
Nargs¶
The nargs parameter controls how many values an argument consumes. Use ?
for zero-or-one, * for zero-or-more, + for one-or-more, or an integer
for an exact count. This is essential for multi-value arguments.
import argclass
class Parser(argclass.Parser):
output: str = argclass.Argument(nargs="?", default="out.txt")
extras: list[str] = argclass.Argument(nargs="*", default=[])
files: list[str] = argclass.Argument(nargs="+")
point: list[float] = argclass.Argument(nargs=3)
parser = Parser()
parser.parse_args([
"--files", "a.txt", "b.txt",
"--point", "1.0", "2.0", "3.0"
])
assert parser.output == "out.txt"
assert parser.extras == []
assert parser.files == ["a.txt", "b.txt"]
assert parser.point == [1.0, 2.0, 3.0]
For better readability, use the Nargs enum instead of string literals:
import argclass
class Parser(argclass.Parser):
optional: str | None = argclass.Argument(
nargs=argclass.Nargs.ZERO_OR_ONE,
default=None
)
multiple: list[str] = argclass.Argument(
nargs=argclass.Nargs.ZERO_OR_MORE,
default=[]
)
parser = Parser()
parser.parse_args(["--multiple", "a", "b", "c"])
assert parser.optional is None
assert parser.multiple == ["a", "b", "c"]
Choices¶
Use choices to restrict an argument to a predefined set of values. The
parser will reject any value not in the list and display valid options in
the error message and --help output.
import argclass
class Parser(argclass.Parser):
log_level: str = argclass.Argument(
choices=["debug", "info", "warning", "error"],
default="info"
)
format: str = argclass.Argument(
choices=["json", "yaml", "toml"],
default="json"
)
parser = Parser()
parser.parse_args(["--log-level", "debug", "--format", "yaml"])
assert parser.log_level == "debug"
assert parser.format == "yaml"
Enum Arguments¶
For type-safe choices, use EnumArgument with Python’s Enum classes. This
provides compile-time safety and IDE autocompletion while automatically
generating valid choices.
import argclass
from enum import Enum
class Color(Enum):
RED = "red"
GREEN = "green"
BLUE = "blue"
class Parser(argclass.Parser):
color: Color = argclass.EnumArgument(Color, default="RED")
parser = Parser()
parser.parse_args([])
assert parser.color == Color.RED
parser.parse_args(["--color", "BLUE"])
assert parser.color == Color.BLUE
The default can be either an enum member or a string name:
import argclass
from enum import IntEnum
class Priority(IntEnum):
LOW = 1
MEDIUM = 2
HIGH = 3
class Parser(argclass.Parser):
# String default - validated at class definition time
level1: Priority = argclass.EnumArgument(Priority, default="MEDIUM")
# Enum member default
level2: Priority = argclass.EnumArgument(Priority, default=Priority.HIGH)
parser = Parser()
parser.parse_args([])
assert parser.level1 == Priority.MEDIUM
assert parser.level2 == Priority.HIGH
Lowercase Choices¶
Use lowercase=True for user-friendly lowercase input:
import argclass
from enum import Enum
class Environment(Enum):
DEVELOPMENT = "dev"
STAGING = "stg"
PRODUCTION = "prod"
class Parser(argclass.Parser):
env: Environment = argclass.EnumArgument(
Environment, default="development", lowercase=True
)
parser = Parser()
parser.parse_args(["--env", "production"])
assert parser.env == Environment.PRODUCTION
Using Enum Values¶
By default, EnumArgument returns the enum member. Use use_value=True to
get the enum’s value instead:
import argclass
from enum import IntEnum
class LogLevel(IntEnum):
DEBUG = 10
INFO = 20
WARNING = 30
class Parser(argclass.Parser):
# Returns enum member
level: LogLevel = argclass.EnumArgument(LogLevel, default="INFO")
# Returns enum value (int)
level_int: int = argclass.EnumArgument(
LogLevel, default="INFO", use_value=True
)
parser = Parser()
parser.parse_args([])
assert parser.level == LogLevel.INFO
assert parser.level_int == 20 # The integer value
Type vs Converter¶
These two parameters serve different purposes in the parsing pipeline:
type: Called for each input string during parsing (before collecting)converter: Called once on the final collected result (after parsing)
Use type for per-value conversion, converter for post-processing the result.
import argclass
class Parser(argclass.Parser):
# type=int converts each string to int
numbers: list[int] = argclass.Argument(nargs="+", type=int)
# type=int converts each string, then converter=set deduplicates
unique: set[int] = argclass.Argument(nargs="+", type=int, converter=set)
# Single converter function
unique_alt: set[int] = argclass.Argument(
nargs="+",
converter=lambda vals: set(map(int, vals))
)
parser = Parser()
parser.parse_args([
"--numbers", "1", "2", "3",
"--unique", "1", "2", "2", "3",
"--unique-alt", "4", "5", "4"
])
assert parser.numbers == [1, 2, 3]
assert parser.unique == {1, 2, 3}
assert parser.unique_alt == {4, 5}
Custom Types¶
Any callable that takes a string and returns the desired type works as a type converter. This enables parsing dates, URLs, custom formats, or any domain-specific value types your application needs.
import argclass
from datetime import datetime
from pathlib import Path
def parse_date(s: str) -> datetime:
return datetime.strptime(s, "%Y-%m-%d")
class Parser(argclass.Parser):
date: datetime = argclass.Argument(type=parse_date)
output: Path = argclass.Argument(type=Path, default=Path("."))
parser = Parser()
parser.parse_args(["--date", "2024-01-15", "--output", "/tmp/output"])
assert parser.date == datetime(2024, 1, 15)
assert parser.output == Path("/tmp/output")