Metadata-Version: 2.4
Name: jps-config-manager
Version: 0.0.0
Summary: A lightweight, layered configuration management library for Python that merges constants, default YAML files, and user-provided configs with optional fallback control.
Author-email: Jaideep Sundaram <jai.python3@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/jai-python3/jps-config-manager
Project-URL: Repository, https://github.com/jai-python3/jps-config-manager
Project-URL: Issues, https://github.com/jai-python3/jps-config-manager/issues
Keywords: cookiecutter,bootstrap,project-generator,automation
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: typer>=0.12.3
Provides-Extra: test
Requires-Dist: pytest>=8.0.0; extra == "test"
Provides-Extra: dev
Requires-Dist: flake8>=7.0.0; extra == "dev"
Requires-Dist: black>=24.0.0; extra == "dev"
Requires-Dist: build>=1.2.1; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
Requires-Dist: isort>=5.13.0; extra == "dev"
Requires-Dist: codecov>=2.1.13; extra == "dev"
Requires-Dist: autoflake>=2.3.1; extra == "dev"
Requires-Dist: pre-commit>=3.8.0; extra == "dev"
Requires-Dist: bandit>=1.7.9; extra == "dev"
Requires-Dist: vulture>=2.11; extra == "dev"
Requires-Dist: flynt>=1.0.1; extra == "dev"
Requires-Dist: pydocstyle>=6.3.0; extra == "dev"
Requires-Dist: darglint>=1.8.1; extra == "dev"
Requires-Dist: mypy>=1.12.1; extra == "dev"
Dynamic: license-file

# jps-config-manager

![Build](https://github.com/jai-python3/jps-config-manager/actions/workflows/test.yml/badge.svg)
![Publish to PyPI](https://github.com/jai-python3/jps-config-manager/actions/workflows/publish-to-pypi.yml/badge.svg)
[![codecov](https://codecov.io/gh/jai-python3/jps-config-manager/branch/main/graph/badge.svg)](https://codecov.io/gh/jai-python3/jps-config-manager)

A lightweight, layered configuration management library for Python that merges constants, default YAML files, and user-provided configs with optional fallback control.

---

## 🚀 Overview

`jps-config-manager` provides a **clean, unified configuration system** for Python applications and CLI tools.  
It supports:

- A project's **Python constants** (e.g., `constants.py`)
- A **default configuration YAML file**
- A **user-supplied configuration file** provided via `--config-file`
- Optional fallback behavior (enabled by default, user-controlled via `default_fallback: false`)
- Strong validation and typed accessors

It is ideal for applications that require predictable, validated, hierarchical configuration loading (e.g., pipelines, services, CLI utilities).

---

## ✨ Features

### ✅ Layered Configuration
Configuration is merged in the following order:

1. Project defaults (constants.py)
2. Default YAML file (e.g., `conf/config.yaml`)
3. User-provided YAML file (`--config-file`)

Later layers override earlier ones.

### ✅ Optional Fallback Support
Users may disable fallback entirely:

```yaml
behavior:
  default_fallback: false
```
When disabled, all required values must be explicitly provided.
Missing keys raise descriptive validation errors.


### ✅ Singleton Manager
A global configuration object ensures consistent access across your application:

```python
from jps_config_manager import ConfigManager

cfg = ConfigManager.instance()
```


### ✅ Typed Getters

Strongly-typed retrieval:

- get_str()
- get_int()
- get_float()
- get_bool()
- get_list()
- get_path()
- get_file()
- get_dir()

### ✅ YAML Loading + Validation
Includes robust YAML loading (safe_load) and validation of required config keys.

### ✅ Dotted-Path Access
Native support for hierarchical lookups:

```python
cfg.get("pipeline.depth_metric")
```

### 📁 Example Project Integration
Project directory layout
```bash
project_a/
├── src/project_a/
│   ├── cli.py
│   ├── constants.py
│   ├── main.py
│   └── ...
├── conf/config.yaml
└── pyproject.toml
```

### constants.py


```python
DEFAULTS = {
    "pipeline": {
        "depth_metric": "median",
        "trim_prop": 0.1,
    },
    "paths": {
        "reference": "/opt/ref.fasta"
    },
    "behavior": {
        "default_fallback": True,
    }
}
```


### CLI entrypoint (cli.py)

```python
import typer
from jps_config_manager import ConfigManager
from project_a import constants

app = typer.Typer()

@app.command()
def run(config_file: str = typer.Option(None, "--config-file")):
    ConfigManager.initialize(
        project_defaults=constants.DEFAULTS,
        default_config_file="conf/config.yaml",
        user_config_file=config_file,
    )

    run_pipeline()
```

### Using the configuration in the application

```python
from jps_config_manager import ConfigManager

def run_pipeline():
    cfg = ConfigManager.instance()

    metric = cfg.get_str("pipeline.depth_metric")
    trim = cfg.get_float("pipeline.trim_prop")
    ref  = cfg.get_file("paths.reference")

    print("Using:", metric, trim, ref)
```

### 🧪 Example Usage (Minimal)
Using fallback (default)
```yaml
pipeline:
  depth_metric: trimmed_mean
```

Result configuration:

- depth_metric → "trimmed_mean"
- trim_prop → 0.1 (default)
- behavior.default_fallback → True

Disabling fallback
```yaml
behavior:
  default_fallback: false

pipeline:
  depth_metric: trimmed_mean
```


Missing trim_prop will raise:

```bash
ValueError: Missing required configuration value at: pipeline.trim_prop
```



### 📦 Installation
```bash
pip install jps-config-manager
```


Or from source:

```bash
make install
```

### 🧪 Development
```bash
make fix && make format && make lint
make test
```

The test suite includes:

- YAML loader tests
- Deep merge tests
- Fallback logic tests
- Validation tests
- ConfigManager singleton tests
- Typed getter tests
- Path resolution tests

### 📜 License
MIT License © Jaideep Sundaram
