Simple class-based argument parsing for python scripts
Project description
argsclass
Simple class-based argument parsing for python scripts
Implementation Note
As of version 0.4.0, argsclass uses argparse as its backend parsing engine while maintaining the same public API. This migration provides:
- Better error messages: More detailed and user-friendly error reporting
- Standard help formatting: Uses argparse's proven help system
- Improved maintainability: Reduced custom code by ~500 lines
- Enhanced compatibility: Leverages argparse's battle-tested parsing logic
The migration is purely internal - all existing code continues to work unchanged.
Class Inspection
The inspect_class function allows you to convert a class definition into a list of ArgSpec objects. This enables you to define your command-line arguments using class attributes with type hints and descriptors.
Basic Usage
from argsclass import inspect_class, positional
class Args:
flag: bool # Boolean attributes become flags
option: str = "default" # Attributes with defaults become options
Name: str = positional(help_text="foo") # Use descriptors for positional args
specs = inspect_class(Args)
# Returns: [FlagArgSpec("flag"), OptionArgSpec("option"), PositionalArgSpec("Name")]
Type Inference
The inspector automatically infers argument types from type hints:
bool→FlagArgSpec(boolean flags)str,int,float→OptionArgSpecorPositionalArgSpec(depending on descriptor)- Attributes with default values →
OptionArgSpec - Attributes with
positional()descriptor →PositionalArgSpec
Descriptors
Use descriptors to create specific argument types:
from argsclass import positional, option, flag
class Args:
# Positional argument
filename = positional(help_text="Input file", arg_type=str)
# Option with choices
format = option(help_text="Output format", choices=["json", "xml"], default="json")
# Flag with aliases
verbose = flag(help_text="Verbose output", aliases={"v"})
Complete Example
from argsclass import inspect_class, positional, option, flag
class MyArgs:
# Boolean flag (inferred from type hint)
verbose: bool
# Option with default
output: str = "output.txt"
# Positional argument
filename = positional(help_text="Input file", arg_type=str)
# Option with choices and aliases
format = option(help_text="Output format", choices=["json", "xml"], aliases={"f"})
# Flag with aliases
debug = flag(help_text="Enable debug mode", aliases={"d"})
# Convert to ArgSpec objects
specs = inspect_class(MyArgs)
for spec in specs:
print(f"{spec.__class__.__name__}: {spec.name}")
## Argument Parsing
The `parse` function can parse command-line arguments using either a list of ArgSpec objects or a class definition.
### Parsing with Classes
```python
from argsclass import parse, positional, option, flag
class MyArgs:
verbose: bool
output: str = "output.txt"
filename = positional(help_text="Input file")
# Parse directly from class
result = parse(MyArgs, ["script.py", "--verbose", "input.txt"])
print(result) # {'verbose': True, 'output': 'output.txt', 'filename': 'input.txt'}
Parsing with ArgSpec Lists
from argsclass import parse, PositionalArgSpec, OptionArgSpec, FlagArgSpec
specs = [
PositionalArgSpec(name="filename"),
OptionArgSpec(name="output", aliases={"o"}),
FlagArgSpec(name="verbose", aliases={"v"})
]
result = parse(specs, ["script.py", "input.txt", "-o", "output.txt", "-v"])
print(result) # {'filename': 'input.txt', 'output': 'output.txt', 'verbose': True}
Ambiguity Protection
The parser includes built-in protection against ambiguous argument configurations that could lead to unpredictable parsing behavior.
Ambiguous Configurations
The following configurations are considered ambiguous and will raise an AmbiguityError:
-
Multiple positional arguments with non-specific cardinality:
class AmbiguousArgs: files1 = positional(cardinality=Cardinality.one_or_more()) files2 = positional(cardinality=Cardinality.zero_or_more())
-
Multiple option arguments with non-specific cardinality:
class AmbiguousArgs: files1 = option(cardinality=Cardinality.one_or_more()) files2 = option(cardinality=Cardinality.zero_or_more())
Note: Mixed positional and option arguments with non-specific cardinality are NOT ambiguous because they are parsed differently:
- Options are parsed by name (e.g.,
--option value) - Positionals are parsed by position
This configuration is valid:
class ValidArgs:
files = positional(cardinality=Cardinality.one_or_more()) # Parsed by position
tags = option(cardinality=Cardinality.zero_or_more()) # Parsed by name
Note: The parsing order matters! Arguments are processed in the order they appear in the class definition. For mixed positional and option arguments, it's recommended to define options first, then positionals:
class RecommendedOrder:
tags = option(cardinality=Cardinality.zero_or_more()) # Processed first
files = positional(cardinality=Cardinality.one_or_more()) # Processed second
Resolving Ambiguities
To resolve ambiguities, consider these approaches:
-
Use specific cardinalities:
class ValidArgs: input_file = positional() # Single value output_file = positional() # Single value files = positional(cardinality=Cardinality.one_or_more()) # Only one with non-specific
-
Reorder arguments (put non-specific cardinality last):
class ValidArgs: input_file = positional() # Specific first output_file = positional() # Specific second extra_files = positional(cardinality=Cardinality.zero_or_more()) # Non-specific last
-
Use different argument types (this is actually always valid):
class ValidArgs: input_file = positional() # Positional for required extra_files = option(cardinality=Cardinality.zero_or_more()) # Option for optional
Disabling Ambiguity Validation
If you need to disable ambiguity validation (not recommended), you can set validate_ambiguities=False:
result = parse(MyArgs, argv, validate_ambiguities=False)
Ambiguity Detection Functions
You can also manually check for ambiguities:
from argsclass import detect_ambiguities, is_ambiguous, get_ambiguity_resolution_suggestions
# Check if configuration is ambiguous
if is_ambiguous(MyArgs):
warnings = detect_ambiguities(MyArgs)
suggestions = get_ambiguity_resolution_suggestions(MyArgs)
print("Ambiguities found:", warnings)
print("Suggestions:", suggestions)
Configuration File Support
argsclass supports loading configuration from files, allowing you to define default values in JSON, YAML, or TOML files while still allowing command-line overrides.
Basic Usage
from argsclass import parse
from typing import List
class Config:
host: str = "localhost"
port: int = 8080
debug: bool = False
files: List[str]
# Load configuration from file
config = parse(Config, config_files=["config.json"])
# Or auto-discover configuration files
config = parse(Config, auto_discover_config=True)
Configuration File Example (config.json)
{
"host": "example.com",
"port": 9000,
"debug": true,
"files": "file1.txt file2.txt"
}
Configuration Functions
from argsclass import load_config_file, find_config_files, merge_configs
# Load a single configuration file
config = load_config_file("config.json")
# Find configuration files automatically
files = find_config_files("myapp") # Looks for myapp.json, myapp.yaml, etc.
# Merge multiple configurations
merged = merge_configs([config1, config2], merge_strategy="last_wins")
Modern Python Type Support
argsclass supports modern Python type hints including the new union syntax from Python 3.10+.
List Types with Automatic Cardinality
from typing import List
from argsclass import parse
class Args:
files: List[str] # Automatically becomes zero_or_more cardinality
ports: List[int] # Supports multiple values
tags: List[str] # Can accept multiple string values
args = parse(Args, ["--files", "a.txt", "b.txt", "--ports", "8080", "8081"])
print(args.files) # ['a.txt', 'b.txt']
print(args.ports) # [8080, 8081]
Union Types (Python 3.10+)
# Python 3.10+ syntax
class Args:
value: str | int | None
level: str | None = "info"
# Traditional syntax (works on all versions)
from typing import Union, Optional
class Args:
value: Union[str, int, None]
level: Optional[str] = "info"
Optional Types
from typing import Optional
from argsclass import parse
class Args:
username: Optional[str] = None
timeout: Optional[int] = 30
debug: Optional[bool] = False # Still becomes a flag
args = parse(Args, ["--username", "admin"])
print(args.username) # "admin"
print(args.timeout) # 30 (default)
print(args.debug) # False (default)
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
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 argsclass-0.4.1.tar.gz.
File metadata
- Download URL: argsclass-0.4.1.tar.gz
- Upload date:
- Size: 47.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d1f8f2d8bcac77bfd19008d11957dfe9d2ac841968906aebce550acc63e0183
|
|
| MD5 |
e8f96ea3aa43c251c43a7ed6727b1b73
|
|
| BLAKE2b-256 |
31eca1e1a25680533df3bdbebd943f362e58565a5d53d4142b8c0ab19dd16ec9
|
Provenance
The following attestation bundles were made for argsclass-0.4.1.tar.gz:
Publisher:
pypi-publish.yml on dotle-git/argsclass
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
argsclass-0.4.1.tar.gz -
Subject digest:
2d1f8f2d8bcac77bfd19008d11957dfe9d2ac841968906aebce550acc63e0183 - Sigstore transparency entry: 562226764
- Sigstore integration time:
-
Permalink:
dotle-git/argsclass@fa12cd48e2d44060c14799a8cda58d874258c921 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/dotle-git
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@fa12cd48e2d44060c14799a8cda58d874258c921 -
Trigger Event:
push
-
Statement type:
File details
Details for the file argsclass-0.4.1-py3-none-any.whl.
File metadata
- Download URL: argsclass-0.4.1-py3-none-any.whl
- Upload date:
- Size: 29.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4d01e75269b588ae5344e0f59ff546f6f62597dadb5a5ac297af17e5e70d628
|
|
| MD5 |
3cfd2a897391b3bc6dcebb6fc32b7f28
|
|
| BLAKE2b-256 |
7d09f04c7d77d43afab84773b546f29ef0ee960b3cb797b70d6b43611c538871
|
Provenance
The following attestation bundles were made for argsclass-0.4.1-py3-none-any.whl:
Publisher:
pypi-publish.yml on dotle-git/argsclass
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
argsclass-0.4.1-py3-none-any.whl -
Subject digest:
c4d01e75269b588ae5344e0f59ff546f6f62597dadb5a5ac297af17e5e70d628 - Sigstore transparency entry: 562226765
- Sigstore integration time:
-
Permalink:
dotle-git/argsclass@fa12cd48e2d44060c14799a8cda58d874258c921 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/dotle-git
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@fa12cd48e2d44060c14799a8cda58d874258c921 -
Trigger Event:
push
-
Statement type: