autoCLI-config


NameautoCLI-config JSON
Version 0.1.5 PyPI version JSON
download
home_pagehttps://github.com/rsanchezgarc/autoCLI_config
SummaryAutomatic configuration management and documentation generation system
upload_time2025-11-03 20:07:21
maintainerNone
docs_urlNone
authorRuben Sanchez-Garcia
requires_python>=3.9
licenseGPL-3.0-or-later
keywords configuration cli documentation argparse dataclass
VCS
bugtrack_url
requirements argParseFromDoc PyYAML
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # autoCLI_config

**Automatic Configuration and Documentation System for Python**

A powerful system for managing configurations and auto-generating documentation in Python applications. Define your documentation once in configuration dataclasses and automatically propagate it to CLI help text, Python docstrings, and API documentation.

## Features

- **Single Source of Truth**: Define parameter documentation once in `PARAM_DOCS` dictionaries
- **Automatic CLI Generation**: Works seamlessly with `argParseFromDoc` to generate rich CLI help
- **Config-Backed Defaults**: Bind function parameters to configuration dataclass attributes
- **Flexible Overrides**: Support for YAML files and command-line config overrides (e.g., `--config train.n_epochs=100`)
- **Type Safety**: Automatic type checking and conversion for config values
- **Hierarchical Configs**: Support for nested configuration dataclasses
- **Validation & Transformation**: Optional validators and transformers for parameter values

## Installation

```bash
pip install autoCLI_config
```

Or install from source:

```bash
git clone https://github.com/rsanchezgarc/autoCLI_config.git
cd autoCLI_config
pip install -e .
```

## Quick Start

### Basic Example

```python
from dataclasses import dataclass
from autoCLI_config import (
    CONFIG_PARAM,
    inject_defaults_from_config,
    inject_docs_from_config_params
)

# 1. Define your configuration with PARAM_DOCS
@dataclass
class TrainConfig:
    """Training configuration."""

    PARAM_DOCS = {
        'learning_rate': 'Learning rate for the optimizer',
        'batch_size': 'Number of samples per training batch',
        'n_epochs': 'Number of training epochs',
    }

    learning_rate: float = 0.001
    batch_size: int = 32
    n_epochs: int = 100

# Create config instance
config = TrainConfig()

# 2. Use decorators to inject config and docs
@inject_docs_from_config_params
@inject_defaults_from_config(config, update_config_with_args=True)
def train(
    learning_rate: float = CONFIG_PARAM(),
    batch_size: int = CONFIG_PARAM(),
    n_epochs: int = CONFIG_PARAM()
):
    """
    Train a machine learning model.

    Args:
        learning_rate: {learning_rate}
        batch_size: {batch_size}
        n_epochs: {n_epochs}
    """
    print(f"Training with lr={learning_rate}, batch_size={batch_size}, epochs={n_epochs}")

# Use the function
train()  # Uses config defaults
train(learning_rate=0.01)  # Override specific params
```

### CLI Integration

```python
from autoCLI_config import ConfigArgumentParser

# Create parser with config integration
parser = ConfigArgumentParser(config_obj=config, verbose=True)
parser.add_args_from_function(train)
args, config_args = parser.parse_args()

# Call function with parsed args
train(**vars(args))
```

Command-line usage:

```bash
# Use defaults from config
python train.py

# Override individual parameters
python train.py --learning-rate 0.01 --batch-size 64

# Override via config system (dot notation)
python train.py --config learning_rate=0.01 batch_size=64

# Load config from YAML file
python train.py --config my_config.yaml

# Show all available config options
python train.py --show-config

# Export current config to YAML
python train.py --export-config output.yaml
```

## Advanced Features

### Hierarchical Configurations

```python
from dataclasses import dataclass, field

@dataclass
class OptimizerConfig:
    PARAM_DOCS = {
        'learning_rate': 'Learning rate for optimizer',
        'weight_decay': 'L2 regularization weight decay',
    }
    learning_rate: float = 0.001
    weight_decay: float = 1e-5

@dataclass
class DataConfig:
    PARAM_DOCS = {
        'batch_size': 'Number of samples per batch',
        'num_workers': 'Number of data loading workers',
    }
    batch_size: int = 32
    num_workers: int = 4

@dataclass
class MainConfig:
    optimizer: OptimizerConfig = field(default_factory=OptimizerConfig)
    data: DataConfig = field(default_factory=DataConfig)

config = MainConfig()

# Access nested config values
@inject_defaults_from_config(config.optimizer)
def train(learning_rate: float = CONFIG_PARAM()):
    """Train with optimizer config."""
    pass

# Or reference across configs
@inject_defaults_from_config(config.optimizer)
def train_advanced(
    learning_rate: float = CONFIG_PARAM(),  # from optimizer config
    batch_size: int = CONFIG_PARAM(config=config.data)  # from data config
):
    """Train with multiple configs."""
    pass
```

### Config Overrides

Override nested config values from command line:

```bash
# Dot notation for nested configs
python train.py --config optimizer.learning_rate=0.01 data.batch_size=64

# Mix YAML and individual overrides
python train.py --config base_config.yaml optimizer.learning_rate=0.01
```

### Validators and Transformers

```python
def positive_int(x: int) -> bool:
    return isinstance(x, int) and x > 0

def to_float(x) -> float:
    return float(x)

@inject_defaults_from_config(config)
def train(
    batch_size: int = CONFIG_PARAM(
        validator=positive_int,
        doc="Batch size (must be positive)"
    ),
    learning_rate: float = CONFIG_PARAM(
        transform=to_float,
        doc="Learning rate"
    )
):
    """Train with validation."""
    pass
```

### Enum Support

```python
from enum import Enum

class OptimizerType(str, Enum):
    ADAM = "adam"
    SGD = "sgd"
    RMSPROP = "rmsprop"

@dataclass
class TrainConfig:
    PARAM_DOCS = {
        'optimizer': 'Optimizer algorithm to use',
    }
    optimizer: OptimizerType = OptimizerType.ADAM

# Automatic string-to-enum conversion
python train.py --optimizer sgd  # Converts "sgd" to OptimizerType.SGD
```

## How It Works

The system consists of three main components:

### 1. CONFIG_PARAM Descriptor

A descriptor class that binds function parameters to configuration attributes:

```python
class CONFIG_PARAM:
    def __init__(self, validator=None, transform=None, doc=None, config=None):
        # Stores validation, transformation, and documentation
        ...
```

### 2. Decorators

**`inject_defaults_from_config(config, update_config_with_args=False)`**
- Binds CONFIG_PARAM instances to config attributes
- Provides default values from configuration
- Optionally updates config when function is called with new values

**`inject_docs_from_config_params(func)`**
- Injects parameter documentation into function docstrings
- Replaces `{param_name}` placeholders with actual documentation
- Works for both CONFIG_PARAM and regular parameters

### 3. Configuration System

**`ConfigOverrideSystem`**
- Parses config assignments (`key=value`)
- Loads YAML configuration files
- Applies overrides to config objects
- Handles type conversion (int, float, Path, Enum, etc.)

**`ConfigArgumentParser`**
- Extends `argParseFromDoc.AutoArgumentParser`
- Adds `--config`, `--show-config`, and `--export-config` arguments
- Manages precedence: direct args > `--config` > defaults
- Detects and reports conflicts

## Documentation Flow

1. **Define** documentation in `PARAM_DOCS` dictionary in config dataclass
2. **Bind** CONFIG_PARAMs to config attributes via `inject_defaults_from_config`
3. **Inject** documentation into docstrings via `inject_docs_from_config_params`
4. **Generate** CLI help automatically with `ConfigArgumentParser`

```
PARAM_DOCS (config class)
    ↓
CONFIG_PARAM.doc (auto-populated)
    ↓
Function docstring (via {placeholder})
    ↓
CLI help text (via argParseFromDoc)
```

## API Reference

### Core Classes

- `CONFIG_PARAM`: Descriptor for config-backed parameters
- `ConfigOverrideSystem`: Utility class for config manipulation
- `ConfigArgumentParser`: CLI parser with config integration

### Decorators

- `inject_defaults_from_config(config, update_config_with_args=False)`
- `inject_docs_from_config_params(func)`

### Utilities

- `merge_dicts(d1, d2)`: Recursively merge dictionaries
- `dataclass_to_dict(obj)`: Convert dataclass to dictionary
- `export_config_to_yaml(config, filepath)`: Export config to YAML
- `check_type_match(expected_type, actual_value)`: Type checking utility


## Performance overhead
Using the decorators adds a non-negligible overhead to each function call, hence we only recommend using them in class builders and outer-loop functions.

## Examples

See the `examples/` directory for complete working examples:

- `basic_example.py`: Simple configuration and CLI
- `multi_config_example.py`: Hierarchical configurations
- `full_workflow.py`: Complete training script pattern

## Testing

Run tests with pytest:

```bash
# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run with coverage
pytest --cov=autoCLI_config --cov-report=term-missing
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT License

## Author

Ruben Sanchez-Garcia (rsanchezgarcia@faculty.ie.edu)

## Acknowledgments

This system was originally developed as part of the [cryoPARES](https://github.com/rsanchezgarc/cryoPARES) project for cryo-EM structure determination, and has been extracted into a standalone package for broader use.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/rsanchezgarc/autoCLI_config",
    "name": "autoCLI-config",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "configuration, cli, documentation, argparse, dataclass",
    "author": "Ruben Sanchez-Garcia",
    "author_email": "Ruben Sanchez-Garcia <rsanchezgarcia@faculty.ie.edu>",
    "download_url": "https://files.pythonhosted.org/packages/d8/26/d56d18d33e2995747329231349f885239110c91bcf410af23c1d8a96b2ba/autocli_config-0.1.5.tar.gz",
    "platform": null,
    "description": "# autoCLI_config\n\n**Automatic Configuration and Documentation System for Python**\n\nA powerful system for managing configurations and auto-generating documentation in Python applications. Define your documentation once in configuration dataclasses and automatically propagate it to CLI help text, Python docstrings, and API documentation.\n\n## Features\n\n- **Single Source of Truth**: Define parameter documentation once in `PARAM_DOCS` dictionaries\n- **Automatic CLI Generation**: Works seamlessly with `argParseFromDoc` to generate rich CLI help\n- **Config-Backed Defaults**: Bind function parameters to configuration dataclass attributes\n- **Flexible Overrides**: Support for YAML files and command-line config overrides (e.g., `--config train.n_epochs=100`)\n- **Type Safety**: Automatic type checking and conversion for config values\n- **Hierarchical Configs**: Support for nested configuration dataclasses\n- **Validation & Transformation**: Optional validators and transformers for parameter values\n\n## Installation\n\n```bash\npip install autoCLI_config\n```\n\nOr install from source:\n\n```bash\ngit clone https://github.com/rsanchezgarc/autoCLI_config.git\ncd autoCLI_config\npip install -e .\n```\n\n## Quick Start\n\n### Basic Example\n\n```python\nfrom dataclasses import dataclass\nfrom autoCLI_config import (\n    CONFIG_PARAM,\n    inject_defaults_from_config,\n    inject_docs_from_config_params\n)\n\n# 1. Define your configuration with PARAM_DOCS\n@dataclass\nclass TrainConfig:\n    \"\"\"Training configuration.\"\"\"\n\n    PARAM_DOCS = {\n        'learning_rate': 'Learning rate for the optimizer',\n        'batch_size': 'Number of samples per training batch',\n        'n_epochs': 'Number of training epochs',\n    }\n\n    learning_rate: float = 0.001\n    batch_size: int = 32\n    n_epochs: int = 100\n\n# Create config instance\nconfig = TrainConfig()\n\n# 2. Use decorators to inject config and docs\n@inject_docs_from_config_params\n@inject_defaults_from_config(config, update_config_with_args=True)\ndef train(\n    learning_rate: float = CONFIG_PARAM(),\n    batch_size: int = CONFIG_PARAM(),\n    n_epochs: int = CONFIG_PARAM()\n):\n    \"\"\"\n    Train a machine learning model.\n\n    Args:\n        learning_rate: {learning_rate}\n        batch_size: {batch_size}\n        n_epochs: {n_epochs}\n    \"\"\"\n    print(f\"Training with lr={learning_rate}, batch_size={batch_size}, epochs={n_epochs}\")\n\n# Use the function\ntrain()  # Uses config defaults\ntrain(learning_rate=0.01)  # Override specific params\n```\n\n### CLI Integration\n\n```python\nfrom autoCLI_config import ConfigArgumentParser\n\n# Create parser with config integration\nparser = ConfigArgumentParser(config_obj=config, verbose=True)\nparser.add_args_from_function(train)\nargs, config_args = parser.parse_args()\n\n# Call function with parsed args\ntrain(**vars(args))\n```\n\nCommand-line usage:\n\n```bash\n# Use defaults from config\npython train.py\n\n# Override individual parameters\npython train.py --learning-rate 0.01 --batch-size 64\n\n# Override via config system (dot notation)\npython train.py --config learning_rate=0.01 batch_size=64\n\n# Load config from YAML file\npython train.py --config my_config.yaml\n\n# Show all available config options\npython train.py --show-config\n\n# Export current config to YAML\npython train.py --export-config output.yaml\n```\n\n## Advanced Features\n\n### Hierarchical Configurations\n\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass OptimizerConfig:\n    PARAM_DOCS = {\n        'learning_rate': 'Learning rate for optimizer',\n        'weight_decay': 'L2 regularization weight decay',\n    }\n    learning_rate: float = 0.001\n    weight_decay: float = 1e-5\n\n@dataclass\nclass DataConfig:\n    PARAM_DOCS = {\n        'batch_size': 'Number of samples per batch',\n        'num_workers': 'Number of data loading workers',\n    }\n    batch_size: int = 32\n    num_workers: int = 4\n\n@dataclass\nclass MainConfig:\n    optimizer: OptimizerConfig = field(default_factory=OptimizerConfig)\n    data: DataConfig = field(default_factory=DataConfig)\n\nconfig = MainConfig()\n\n# Access nested config values\n@inject_defaults_from_config(config.optimizer)\ndef train(learning_rate: float = CONFIG_PARAM()):\n    \"\"\"Train with optimizer config.\"\"\"\n    pass\n\n# Or reference across configs\n@inject_defaults_from_config(config.optimizer)\ndef train_advanced(\n    learning_rate: float = CONFIG_PARAM(),  # from optimizer config\n    batch_size: int = CONFIG_PARAM(config=config.data)  # from data config\n):\n    \"\"\"Train with multiple configs.\"\"\"\n    pass\n```\n\n### Config Overrides\n\nOverride nested config values from command line:\n\n```bash\n# Dot notation for nested configs\npython train.py --config optimizer.learning_rate=0.01 data.batch_size=64\n\n# Mix YAML and individual overrides\npython train.py --config base_config.yaml optimizer.learning_rate=0.01\n```\n\n### Validators and Transformers\n\n```python\ndef positive_int(x: int) -> bool:\n    return isinstance(x, int) and x > 0\n\ndef to_float(x) -> float:\n    return float(x)\n\n@inject_defaults_from_config(config)\ndef train(\n    batch_size: int = CONFIG_PARAM(\n        validator=positive_int,\n        doc=\"Batch size (must be positive)\"\n    ),\n    learning_rate: float = CONFIG_PARAM(\n        transform=to_float,\n        doc=\"Learning rate\"\n    )\n):\n    \"\"\"Train with validation.\"\"\"\n    pass\n```\n\n### Enum Support\n\n```python\nfrom enum import Enum\n\nclass OptimizerType(str, Enum):\n    ADAM = \"adam\"\n    SGD = \"sgd\"\n    RMSPROP = \"rmsprop\"\n\n@dataclass\nclass TrainConfig:\n    PARAM_DOCS = {\n        'optimizer': 'Optimizer algorithm to use',\n    }\n    optimizer: OptimizerType = OptimizerType.ADAM\n\n# Automatic string-to-enum conversion\npython train.py --optimizer sgd  # Converts \"sgd\" to OptimizerType.SGD\n```\n\n## How It Works\n\nThe system consists of three main components:\n\n### 1. CONFIG_PARAM Descriptor\n\nA descriptor class that binds function parameters to configuration attributes:\n\n```python\nclass CONFIG_PARAM:\n    def __init__(self, validator=None, transform=None, doc=None, config=None):\n        # Stores validation, transformation, and documentation\n        ...\n```\n\n### 2. Decorators\n\n**`inject_defaults_from_config(config, update_config_with_args=False)`**\n- Binds CONFIG_PARAM instances to config attributes\n- Provides default values from configuration\n- Optionally updates config when function is called with new values\n\n**`inject_docs_from_config_params(func)`**\n- Injects parameter documentation into function docstrings\n- Replaces `{param_name}` placeholders with actual documentation\n- Works for both CONFIG_PARAM and regular parameters\n\n### 3. Configuration System\n\n**`ConfigOverrideSystem`**\n- Parses config assignments (`key=value`)\n- Loads YAML configuration files\n- Applies overrides to config objects\n- Handles type conversion (int, float, Path, Enum, etc.)\n\n**`ConfigArgumentParser`**\n- Extends `argParseFromDoc.AutoArgumentParser`\n- Adds `--config`, `--show-config`, and `--export-config` arguments\n- Manages precedence: direct args > `--config` > defaults\n- Detects and reports conflicts\n\n## Documentation Flow\n\n1. **Define** documentation in `PARAM_DOCS` dictionary in config dataclass\n2. **Bind** CONFIG_PARAMs to config attributes via `inject_defaults_from_config`\n3. **Inject** documentation into docstrings via `inject_docs_from_config_params`\n4. **Generate** CLI help automatically with `ConfigArgumentParser`\n\n```\nPARAM_DOCS (config class)\n    \u2193\nCONFIG_PARAM.doc (auto-populated)\n    \u2193\nFunction docstring (via {placeholder})\n    \u2193\nCLI help text (via argParseFromDoc)\n```\n\n## API Reference\n\n### Core Classes\n\n- `CONFIG_PARAM`: Descriptor for config-backed parameters\n- `ConfigOverrideSystem`: Utility class for config manipulation\n- `ConfigArgumentParser`: CLI parser with config integration\n\n### Decorators\n\n- `inject_defaults_from_config(config, update_config_with_args=False)`\n- `inject_docs_from_config_params(func)`\n\n### Utilities\n\n- `merge_dicts(d1, d2)`: Recursively merge dictionaries\n- `dataclass_to_dict(obj)`: Convert dataclass to dictionary\n- `export_config_to_yaml(config, filepath)`: Export config to YAML\n- `check_type_match(expected_type, actual_value)`: Type checking utility\n\n\n## Performance overhead\nUsing the decorators adds a non-negligible overhead to each function call, hence we only recommend using them in class builders and outer-loop functions.\n\n## Examples\n\nSee the `examples/` directory for complete working examples:\n\n- `basic_example.py`: Simple configuration and CLI\n- `multi_config_example.py`: Hierarchical configurations\n- `full_workflow.py`: Complete training script pattern\n\n## Testing\n\nRun tests with pytest:\n\n```bash\n# Install dev dependencies\npip install -e \".[dev]\"\n\n# Run tests\npytest\n\n# Run with coverage\npytest --cov=autoCLI_config --cov-report=term-missing\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nMIT License\n\n## Author\n\nRuben Sanchez-Garcia (rsanchezgarcia@faculty.ie.edu)\n\n## Acknowledgments\n\nThis system was originally developed as part of the [cryoPARES](https://github.com/rsanchezgarc/cryoPARES) project for cryo-EM structure determination, and has been extracted into a standalone package for broader use.\n",
    "bugtrack_url": null,
    "license": "GPL-3.0-or-later",
    "summary": "Automatic configuration management and documentation generation system",
    "version": "0.1.5",
    "project_urls": {
        "Bug Reports": "https://github.com/rsanchezgarc/autoCLI_config/issues",
        "Homepage": "https://github.com/rsanchezgarc/autoCLI_config",
        "Source": "https://github.com/rsanchezgarc/autoCLI_config"
    },
    "split_keywords": [
        "configuration",
        " cli",
        " documentation",
        " argparse",
        " dataclass"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "27126cd952a3a3108a45005f808e6aed2fcebd468cd267ef3f1540d1e223ff07",
                "md5": "35c63f5aac42d8b89e8772a35334c4a2",
                "sha256": "9d3d87ca0811f88c0d90459e44491dc48a0984d050c3937bd4f52c3d8fadd67e"
            },
            "downloads": -1,
            "filename": "autocli_config-0.1.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "35c63f5aac42d8b89e8772a35334c4a2",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 32484,
            "upload_time": "2025-11-03T20:07:20",
            "upload_time_iso_8601": "2025-11-03T20:07:20.086757Z",
            "url": "https://files.pythonhosted.org/packages/27/12/6cd952a3a3108a45005f808e6aed2fcebd468cd267ef3f1540d1e223ff07/autocli_config-0.1.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d826d56d18d33e2995747329231349f885239110c91bcf410af23c1d8a96b2ba",
                "md5": "495071cb9e59e8210311d56f450f3705",
                "sha256": "5c42fd3fd3a79605071be857aa4e6b6e3ececed3d7229435bb5a0db66c0f6c8a"
            },
            "downloads": -1,
            "filename": "autocli_config-0.1.5.tar.gz",
            "has_sig": false,
            "md5_digest": "495071cb9e59e8210311d56f450f3705",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 44049,
            "upload_time": "2025-11-03T20:07:21",
            "upload_time_iso_8601": "2025-11-03T20:07:21.073002Z",
            "url": "https://files.pythonhosted.org/packages/d8/26/d56d18d33e2995747329231349f885239110c91bcf410af23c1d8a96b2ba/autocli_config-0.1.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-11-03 20:07:21",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "rsanchezgarc",
    "github_project": "autoCLI_config",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "argParseFromDoc",
            "specs": [
                [
                    ">=",
                    "0.0.8"
                ]
            ]
        },
        {
            "name": "PyYAML",
            "specs": [
                [
                    ">=",
                    "5.1"
                ]
            ]
        }
    ],
    "lcname": "autocli-config"
}
        
Elapsed time: 2.05239s