Skip to main content

argclass

Coverage Actions Latest Version Python Versions License

Declarative CLI parser with type hints, config files, and environment variables.

Build type-safe command-line interfaces using Python classes. Zero dependencies.

Documentation | PyPI

Installation

pip install argclass

Quick Start

import argclass

class Server(argclass.Parser):
    host: str = "127.0.0.1"
    port: int = 8080
    debug: bool = False

server = Server()
server.parse_args(["--host", "0.0.0.0", "--port", "9000", "--debug"])
assert server.host == "0.0.0.0"
assert server.port == 9000
assert server.debug is True
$ python server.py --host 0.0.0.0 --port 9000 --debug

Features

Feature argclass argparse click/typer
Type hints Yes No Yes
IDE autocompletion Yes No Yes
Config files Built-in No No
Environment variables Built-in No Plugin
Secret masking Built-in No No
Dependencies stdlib stdlib Many

Examples

Type Annotations

import argclass
from pathlib import Path

class Parser(argclass.Parser):
    name: str                    # required
    count: int = 10              # optional with default
    config: Path | None = None   # optional path
    files: list[str]             # list of values

parser = Parser()
parser.parse_args(["--name", "test", "--files", "a.txt", "b.txt"])
assert parser.name == "test"
assert parser.count == 10
assert parser.files == ["a.txt", "b.txt"]

Argument Groups

import argclass

class DatabaseGroup(argclass.Group):
    host: str = "localhost"
    port: int = 5432

class Parser(argclass.Parser):
    debug: bool = False
    db = DatabaseGroup()

parser = Parser()
parser.parse_args(["--db-host", "db.example.com", "--db-port", "3306"])
assert parser.db.host == "db.example.com"
assert parser.db.port == 3306

Groups can also contain other Groups. Names join with - (CLI), _ (env vars), or . (INI/TOML sections):

import argclass

class Credentials(argclass.Group):
    username: str = "admin"
    password: str = "secret"

class Endpoint(argclass.Group):
    host: str = "localhost"
    credentials: Credentials = Credentials()

class Parser(argclass.Parser):
    endpoint: Endpoint = Endpoint()

parser = Parser()
parser.parse_args([
    "--endpoint-host", "api.example.com",
    "--endpoint-credentials-username", "root",
])
assert parser.endpoint.host == "api.example.com"
assert parser.endpoint.credentials.username == "root"

See Groups for nested groups in config files, environment variables, and --help.

Configuration Files

Load default values from configuration files. INI by default, JSON/TOML via config_parser_class. See Config Files for details.

import argclass
from pathlib import Path
from tempfile import NamedTemporaryFile

class Parser(argclass.Parser):
    host: str = "localhost"
    port: int = 8080

# Config file content
CONFIG_CONTENT = """
[DEFAULT]
host = example.com
port = 9000
"""

with NamedTemporaryFile(mode="w", suffix=".ini", delete=False) as f:
    f.write(CONFIG_CONTENT)
    config_path = f.name

parser = Parser(config_files=[config_path])
parser.parse_args([])
assert parser.host == "example.com"
assert parser.port == 9000

Path(config_path).unlink()

Tip: Use os.getenv() for dynamic config paths. Multiple files are merged (later overrides earlier), enabling global defaults with user overrides:

import os
import argclass

class Parser(argclass.Parser):
    host: str = "localhost"

parser = Parser(config_files=[
    os.getenv("MYAPP_CONFIG", "/etc/myapp/config.ini"),  # Global defaults
    "~/.config/myapp.ini",  # User overrides (partial config OK)
])

To let the end user choose the config file, add config_argument="--config" — the flag's file becomes argument defaults (CLI and env vars still win):

import argclass
from pathlib import Path
from tempfile import NamedTemporaryFile

class Parser(argclass.Parser):
    host: str = "localhost"
    port: int = 8080

with NamedTemporaryFile(mode="w", suffix=".ini", delete=False) as f:
    f.write("[DEFAULT]\nhost = example.com\nport = 9000\n")
    config_path = f.name

parser = Parser(config_argument="--config")
parser.parse_args(["--config", config_path, "--port", "1234"])
assert parser.host == "example.com"   # default from the file
assert parser.port == 1234            # CLI still wins

Path(config_path).unlink()

Environment Variables

import os
import argclass

os.environ["APP_HOST"] = "env.example.com"
os.environ["APP_DEBUG"] = "true"

class Parser(argclass.Parser):
    host: str = "localhost"
    debug: bool = False

parser = Parser(auto_env_var_prefix="APP_")
parser.parse_args([])
assert parser.host == "env.example.com"
assert parser.debug is True

del os.environ["APP_HOST"]
del os.environ["APP_DEBUG"]

Generating Config Files

argclass can WRITE config files for a parser — the inverse of reading them. Wire a --generate-config flag and end users dump a working config straight from the CLI:

import argclass

class CLI(argclass.Parser):
    host: str = "localhost"
    port: int = 8080
    generate_config = argclass.Argument(
        action=argclass.GenerateConfigAction,
        generator=argclass.TOMLConfigGenerator,
        metavar="FILE",
    )
myapp --generate-config /etc/myapp.toml   # write a file
myapp --generate-config -                 # print to stdout

The action captures values from class defaults, config_files=, env vars, and any CLI flags that appear BEFORE --generate-config, then exits with status 0.

Four built-in generators: INIConfigGenerator, JSONConfigGenerator, TOMLConfigGenerator, EnvConfigGenerator. Subclass ConfigGenerator to add your own. See Generating Config Files for the full guide (multi-format wiring, env-listings, format conversion, NonConfigAction opt-out for fire-and-exit actions).

Subcommands

import argclass

class ServeCommand(argclass.Parser):
    """Start the server."""
    host: str = "0.0.0.0"
    port: int = 8080

    def __call__(self) -> int:
        print(f"Serving on {self.host}:{self.port}")
        return 0

class CLI(argclass.Parser):
    verbose: bool = False
    serve = ServeCommand()

if __name__ == "__main__":
    cli = CLI()
    cli.parse_args()
    exit(cli())
$ python app.py serve --host 127.0.0.1 --port 9000
Serving on 127.0.0.1:9000

Secrets

import argclass

class Parser(argclass.Parser):
    api_key: str = argclass.Secret(env_var="API_KEY")

# SecretString prevents accidental logging
# repr() returns '******', str() returns actual value

Argparse Passthrough

Argument() forwards any extra keyword arguments to argparse.add_argument(), so argparse-specific options like version= work out of the box:

import argclass

class CLI(argclass.Parser):
    version = argclass.Argument(
        "-V", "--version",
        action=argclass.Actions.VERSION,
        version="myapp/1.2.3",
    )

try:
    CLI().parse_args(["--version"])
except SystemExit as exc:
    assert exc.code == 0

The same passthrough lets you ship custom argparse.Action subclasses that take their own constructor parameters — for example, a --check-updates flag that queries PyPI:

import json, urllib.request
from importlib.metadata import version as get_version

import argclass

class CheckPyPIUpdate(argclass.NonConfigAction):
    def __init__(self, option_strings, dest, package_name, **kwargs):
        kwargs.setdefault("nargs", 0)
        self.package_name = package_name
        super().__init__(option_strings, dest, **kwargs)

    def __call__(self, parser, namespace, values, option_string=None):
        url = f"https://pypi.org/pypi/{self.package_name}/json"
        with urllib.request.urlopen(url, timeout=5) as r:
            latest = json.load(r)["info"]["version"]
        current = get_version(self.package_name)
        setattr(namespace, self.dest, {
            "current": current,
            "latest": latest,
            "up_to_date": current == latest,
        })

class CLI(argclass.Parser):
    # --check-updates is auto-derived from the attribute name
    check_updates = argclass.Argument(
        action=CheckPyPIUpdate,
        package_name="argclass",  # passthrough kwarg
    )

cli = CLI()
cli.parse_args(["--check-updates"])
assert cli.check_updates["current"] == get_version("argclass")
assert isinstance(cli.check_updates["latest"], str)
assert isinstance(cli.check_updates["up_to_date"], bool)
assert "check_updates" not in argclass.INIConfigGenerator().dump_to_string(cli)

See Argparse Passthrough Kwargs for the full pattern.

Interactive Examples

Run python -m argclass to explore all features interactively. Each subcommand prints its own source code and demonstrates a different feature:

python -m argclass basic          # str, int, float, bool, Optional
python -m argclass types          # Literal, list, Enum, frozenset
python -m argclass groups         # argument groups with prefixes
python -m argclass secrets        # Secret and SecretString masking
python -m argclass env            # environment variable integration
python -m argclass subcommands    # nested subcommands with __call__

Documentation

Full documentation at docs.argclass.com:

Release files for argclass 1.10.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for argclass 1.10.3
File Size Uploaded
argclass-1.10.3.tar.gz 115.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for argclass 1.10.3
File Interpreter ABI Platform
argclass-1.10.3-py3-none-any.whl Python 3 none any Details

Total release size: 171.9 kB

Release files / argclass-1.10.3.tar.gz

Download URL argclass-1.10.3.tar.gz
Size 115.8 kB
Tags Source
SHA-256 checksum
How to use checksums
4828d733d819cabef2543aa2c63f6993a27f3c1438e357009e7ca335e119c151
BLAKE2b-256 checksum
How to use checksums
07ed0e87015bc8438c4fbe4949c8c5d1c018393c85db7a8c60d8e978b7ae47f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release files / argclass-1.10.3-py3-none-any.whl

Download URL argclass-1.10.3-py3-none-any.whl
Size 56.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c05f4cd92f1f2b7e07c6b72bf135a2271c5c28a77a12666cb52f5be14010b46f
BLAKE2b-256 checksum
How to use checksums
ee8f295c489fcc496c1bd78b48c23878194bb28b156dc05a1a17e621dcf2c6c6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release history Release notifications | RSS feed

1.11.1

2 release files

1.11.0

2 release files

This release

1.10.3 This release

2 release files

1.10.2

2 release files

1.10.1

2 release files

1.10.0

2 release files

1.9.2

2 release files

1.9.1

2 release files

1.9.0

2 release files

1.8.1

2 release files

1.8.0

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.2

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.11.0

2 release files

0.10.1

2 release files

0.10.0

2 release files

0.9.2

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

1 release file

0.4.0

1 release file

0.3.0

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page