Metadata-Version: 2.4
Name: CfgForge
Version: 0.1.2
Summary: Multi-source configuration loader and merger for env / json / yaml / toml / ini / properties / xml
Author: _COME_HERE_
License: MIT
Keywords: config,configuration,settings,env,yaml,toml,ini,properties,xml
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: yaml
Requires-Dist: pyyaml>=6.0; extra == "yaml"
Provides-Extra: toml
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "toml"
Provides-Extra: all
Requires-Dist: pyyaml>=6.0; extra == "all"
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "all"

# CfgForge

Multi-source configuration loader and merger for Python.
Supports `env`, `json`, `yaml`, `ini`, `properties`, `xml`, and `toml` — with priority-based merging,
dot-path access, and type checking.

## Features

- Load multiple config sources in order; later ones override earlier ones
- Dot-path access: `config.get("db.host")`
- Type validation: `config.expect("db.port", int)`
- Required keys: `config.get("api.key", required=True)`
- Optional dependencies: install only what you need
- Supports 7 formats: env, json, yaml, toml, ini, properties, xml
- Clear error messages for missing keys, wrong types, and parse failures

## Installation

```bash
pip install CfgForge
```

With YAML support:

```bash
pip install CfgForge[yaml]
```

With all optional formats:

```bash
pip install CfgForge[all]
```

## Quick Start

```python
from CfgForge import config

# Load sources (later overrides earlier)
config.load(".env", "config.yaml", defaults={"db.host": "localhost"})

# Read by dot-path
host = config.get("db.host")                # "localhost"
port = config.get("db.port", 5432)          # with default
key  = config.get("api.key", required=True) # raises if missing

# Type check
port = config.expect("db.port", int)
```

## Supported Formats

|   Format   |     Extension    |          Dependency           |
|------------|------------------|-------------------------------|
| env        | `.env`           | none                          |
| JSON       | `.json`          | none                          |
| YAML       | `.yaml` / `.yml` | `pyyaml`                      |
| TOML       | `.toml`          | `tomllib` (3.11+) or `tomli`  |
| INI        | `.ini`           | none                          |
| Properties | `.properties`    | none                          |
| XML        | `.xml`           | none                          |    

## API Reference

### `config.load(*paths, defaults=None)`

Load one or more config files. Later sources override earlier ones.
`defaults` has the lowest priority.

```python
config.load(".env", "config.yaml", defaults={"db.host": "localhost"})
```

### `config.get(key, default=None, required=False)`

Read a value by dot-path.

```python
config.get("db.host")                 # None if missing
config.get("db.host", "localhost")    # fallback value
config.get("db.host", required=True)  # raises if missing
```

### `config.expect(key, type_)`

Read a value and validate its type.

```python
port = config.expect("db.port", int)   # raises ConfigTypeError if not int
```

### `config.has(key)`

Check whether a key exists.

```python
if config.has("db.password"):
    ...
```

### `config.update(data)`

Inject config manually (useful for tests or runtime overrides).

```python
config.update({"db": {"host": "localhost"}})
```

### `config.all()`

Return a shallow copy of all config data.

```python
data = config.all()
```

## Exception Hierarchy

```
CfgForgeError
├── ConfigNotFoundError
├── ConfigTypeError
└── ConfigFileError
```

Catch all at once:

```python
from CfgForge import CfgForgeError

try:
    config.load("config.yaml")
    config.get("db.host", required=True)
except CfgForgeError as e:
    print(f"Config error: {e}")
```

## License

MIT
