Declarative CLI parser with type hints, config files, and environment variables - zero dependencies
Project description
argclass
Declarative CLI parser with type hints, config files, and environment variables.
Build type-safe command-line interfaces using Python classes. Zero dependencies.
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)
])
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. Useful for scaffolding sample configs, dumping the running state, or exporting env-var listings.
import argclass
class Database(argclass.Group):
host: str = "localhost"
port: int = 5432
class CLI(argclass.Parser):
debug: bool = False
db: Database = Database()
parser = CLI()
ini = argclass.INIConfigGenerator().dump_to_string(parser)
assert "[DEFAULT]" in ini
assert "[db]" in ini
env = argclass.EnvConfigGenerator().dump_to_string(
CLI(auto_env_var_prefix="APP_"),
)
assert "APP_DEBUG=false" in env
assert "APP_DB_HOST=localhost" in env
Ship a --generate-config FILE flag with the built-in action
(supply - for stdout):
import argclass
class CLI(argclass.Parser):
host: str = "localhost"
generate = argclass.Argument(
"--generate-config",
action=argclass.GenerateConfigAction,
generator=argclass.TOMLConfigGenerator,
)
Four built-in generators: INIConfigGenerator,
JSONConfigGenerator, TOMLConfigGenerator, EnvConfigGenerator.
Subclass ConfigGenerator for custom formats. See Generating
Config Files
for the full guide.
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 argparse, json, urllib.request
from importlib.metadata import version as get_version
class CheckPyPIUpdate(argparse.Action):
def __init__(self, option_strings, dest, package_name, **kwargs):
kwargs.setdefault("nargs", 0)
kwargs.setdefault("default", argparse.SUPPRESS)
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)
if current == latest:
parser.exit(0, f"{self.package_name} {current} is up to date\n")
parser.exit(0, f"Update available: {current} -> {latest}\n")
class CLI(argclass.Parser):
# --check-updates is auto-derived from the attribute name
check_updates = argclass.Argument(
action=CheckPyPIUpdate,
package_name="argclass", # passthrough kwarg
)
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:
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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 argclass-1.9.0.tar.gz.
File metadata
- Download URL: argclass-1.9.0.tar.gz
- Upload date:
- Size: 97.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23579d3e98517312d59a42bb4eed83f2282171e4d49cfc25a0c7c2369a1224dd
|
|
| MD5 |
0186e943cacb552ecfd308bff65e3fc5
|
|
| BLAKE2b-256 |
ea11294e42790d45b37946c5ab46937466e9256968e6d6e9e7c6af3a9b908109
|
Provenance
The following attestation bundles were made for argclass-1.9.0.tar.gz:
Publisher:
publish.yml on mosquito/argclass
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
argclass-1.9.0.tar.gz -
Subject digest:
23579d3e98517312d59a42bb4eed83f2282171e4d49cfc25a0c7c2369a1224dd - Sigstore transparency entry: 1594526481
- Sigstore integration time:
-
Permalink:
mosquito/argclass@4c755e843d8e5f53eb07c21bcbf409fe17165b1e -
Branch / Tag:
refs/tags/1.9.0 - Owner: https://github.com/mosquito
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4c755e843d8e5f53eb07c21bcbf409fe17165b1e -
Trigger Event:
release
-
Statement type:
File details
Details for the file argclass-1.9.0-py3-none-any.whl.
File metadata
- Download URL: argclass-1.9.0-py3-none-any.whl
- Upload date:
- Size: 48.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
78ec66b6355bc7011b0a037790b65a274d8f026b639b00f1f2aecec07d8c7c42
|
|
| MD5 |
14bc0a266e0c72be92150da6dd538742
|
|
| BLAKE2b-256 |
0e9961a785e5b8153d24075044e2fceb3a4f92ec590100e7e81c241db1426ccd
|
Provenance
The following attestation bundles were made for argclass-1.9.0-py3-none-any.whl:
Publisher:
publish.yml on mosquito/argclass
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
argclass-1.9.0-py3-none-any.whl -
Subject digest:
78ec66b6355bc7011b0a037790b65a274d8f026b639b00f1f2aecec07d8c7c42 - Sigstore transparency entry: 1594526535
- Sigstore integration time:
-
Permalink:
mosquito/argclass@4c755e843d8e5f53eb07c21bcbf409fe17165b1e -
Branch / Tag:
refs/tags/1.9.0 - Owner: https://github.com/mosquito
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4c755e843d8e5f53eb07c21bcbf409fe17165b1e -
Trigger Event:
release
-
Statement type: