⚙️ spargear
A powerful yet simple Python library for declarative command-line argument parsing, built on top of argparse. spargear enables elegant, type-safe definitions of CLI arguments and subcommands with minimal boilerplate.
Why spargear?
- ✅ Declarative: Define your CLI arguments neatly using Python data classes.
- 🚀 Typed and Safe: Leveraging Python typing and dataclasses to ensure type safety and developer productivity.
- 🔧 Flexible: Supports complex argument parsing scenarios, including subcommands and nested configurations.
- 📦 Minimal Dependencies: Pure Python, built directly upon the reliable
argparsemodule. - 🎯 Modern API: Beautiful
@subcommandor@subcommandclassdecorator for intuitive subcommand definition.
Installation
Install with pip:
pip install spargear
Quick Start
Define your arguments:
from typing import Annotated, Optional
from spargear import BaseArguments
class MyArgs(BaseArguments):
input_file: Annotated[Optional[str], "-i", "--input"] = None
"""Input file path"""
verbose: Annotated[bool, "-v", "--verbose"] = False
"""Enable verbose output"""
# Parse the command-line arguments
args = MyArgs()
# Access the parsed arguments
input_file: Optional[str] = args.input_file
# input_file: str | None = args.input_file.value
verbose: bool = args.verbose # store_true `-v` or `--verbose` to True
print(f"Input file: {input_file}")
print(f"Verbose mode: {verbose}")
Run your CLI:
python app.py --input example.txt --verbose
Subcommands with @subcommand or @subcommandclass decorator
The easiest and most intuitive way to define subcommands is using the @subcommand or @subcommandclass decorator:
from spargear import BaseArguments, subcommandclass
class GitCLI(BaseArguments):
"""A Git-like CLI tool."""
@subcommandclass(help="Initialize a new repository")
class Init(BaseArguments):
"""Initialize a new Git repository."""
NAME: str
@subcommandclass(help="Record changes to the repository")
class Commit(BaseArguments):
"""Record changes."""
message: str
amend: bool = False
# Parse and use
args = GitCLI()
# Access the active subcommand
args.inspect(GitCLI.Init, lambda init_args: print(f"Initializing project: {init_args.NAME}"))
args.inspect(
GitCLI.Commit,
lambda commit_args: print(f"Committing: {commit_args.message} (amend: {commit_args.amend}"),
)
Run your CLI:
python app.py init my_project
python app.py commit -m "Initial commit" --amend
@subcommand Features
The @subcommand decorator automatically:
- Extracts the subcommand name from the method name (or use
name=parameter to override) - Uses the method's docstring as help text and description
- Treats the method as a factory that returns the argument class
- No need for
@staticmethod- the decorator handles it automatically!
class MyApp(BaseArguments):
@subcommand() # Name will be "serve", help from docstring
def serve():
"""Start the development server.
Launches a local development server on the specified port
with hot reload capabilities.
"""
return ServeArguments
@subcommand(name="db-migrate", help="Run database migrations")
def database_migrate(): # Custom name overrides method name
return MigrateArguments
Advanced Usage
Manual SubcommandSpec (Alternative approach)
For more control or complex scenarios, you can still use SubcommandSpec directly:
from spargear import BaseArguments, SubcommandSpec, ArgumentSpec
class InitArgs(BaseArguments):
name: ArgumentSpec[str] = ArgumentSpec(["name"], help="Project name")
class CommitArgs(BaseArguments):
message: ArgumentSpec[str] = ArgumentSpec(["-m"], required=True, help="Commit message")
class GitCLI(BaseArguments):
init = SubcommandSpec("init", InitArgs, help="Initialize a new repository")
commit = SubcommandSpec("commit", CommitArgs, help="Commit changes")
Note: The @subcommand decorator is the recommended approach for most use cases as it provides a cleaner, more maintainable syntax.
Default Factories
Generate dynamic values at parse time:
import uuid
from datetime import datetime
from spargear import BaseArguments, ArgumentSpec
class AppConfig(BaseArguments):
# Method 1: Direct callable assignment (auto-detected)
session_id: str = lambda: str(uuid.uuid4())
# Method 2: Explicit ArgumentSpec with default_factory
log_file: ArgumentSpec[str] = ArgumentSpec(
["--log-file"],
default_factory=lambda: f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
help="Log file path"
)
name: str = "myapp" # Regular default value
config = AppConfig()
print(f"Session ID: {config.session_id}") # Unique UUID each time
print(f"Log file: {config.log_file.unwrap()}") # Timestamp-based filename
Configuration Management
Save and load configurations:
from spargear import BaseArguments
from typing import List
class ServerConfig(BaseArguments):
host: str = "localhost"
port: int = 8080
debug: bool = False
allowed_hosts: List[str] = ["127.0.0.1", "localhost"]
# Create and configure
config = ServerConfig(["--port", "3000", "--debug"])
# Convert to dataclass
config_dc = config.to_dataclass()
print(f"Dataclass: {config_dc}")
# Save to JSON
config.save_config("server.json")
# Load from JSON with command-line overrides
loaded_config = ServerConfig.load_config("server.json", args=["--port", "9000"])
print(f"Port: {loaded_config.port}") # 9000 (overridden)
print(f"Debug: {loaded_config.debug}") # True (from file)
# Update from dictionary
config.update_from_dict({"host": "0.0.0.0", "port": 5000})
API Reference
@subcommand Decorator
@subcommand(name=None, help="", description=None, argument_class=None)
def method_name():
return ArgumentClass
Parameters:
name(optional): Override the subcommand name (defaults to method name)help(optional): Brief help text (defaults to first line of docstring)description(optional): Detailed description (defaults to rest of docstring)argument_class(optional): Directly specify the argument class instead of using the factory
BaseArguments Methods
Serialization
to_dict() -> Dict[str, Any]- Convert to dictionaryto_json() -> str- Serialize to JSONto_pickle() -> bytes- Serialize to pickle formatto_dataclass()- Convert to dataclass instance
Deserialization
from_dict(data, args=None)- Create from dictionaryfrom_json(json_data, args=None)- Create from JSON string/filefrom_pickle(file_path, args=None)- Create from pickle file
Configuration Management
save_config(file_path, format="json")- Save configurationload_config(file_path, format=None, args=None)- Load configurationupdate_from_dict(data)- Update current instance
Subcommand Access
last_subcommand- Get the active subcommand instance (if any)
ArgumentSpec Features
Default Factories
ArgumentSpec(
name_or_flags=["--arg"],
default_factory=lambda: generate_value(), # Called at parse time
help="Description"
)
Compatibility
- Python 3.8+
License
MIT
Metadata
Release files for spargear 0.2.20
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| spargear-0.2.20.tar.gz | 30.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spargear-0.2.20-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 50.2 kB
Release files / spargear-0.2.20.tar.gz
| Download URL | spargear-0.2.20.tar.gz |
|---|---|
| Size | 30.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3347a88c734cc5fe0a8e0865c1762a7ac0dc75baf89212035de68d2ceeb925b9
|
|
BLAKE2b-256 checksum How to use checksums |
c40d7c3e894e01a4bd849b1a6da5a13de96bf6280c92777b30a9710deccf67e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.5
|
Release files / spargear-0.2.20-py3-none-any.whl
| Download URL | spargear-0.2.20-py3-none-any.whl |
|---|---|
| Size | 19.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c6556df78af5b5bbd59a5d45d86d32685c8405d9bf46b2c3d052bf3092dca762
|
|
BLAKE2b-256 checksum How to use checksums |
81977b736a778962b1c27c544bbad2848afdf93ecff7452d84cf671588d0f5b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.5
|