Metadata-Version: 2.1
Name: wexample-helpers-yaml
Version: 7.0.2
Summary: Reads and writes YAML files, replaces ${VAR} placeholders, and provides a mixin for loading env config from YAML.
Author-Email: weeger <contact@wexample.com>
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Project-URL: homepage, https://github.com/wexample/python-helpers-yaml
Requires-Python: >=3.10
Requires-Dist: attrs>=23.1.0
Requires-Dist: cattrs>=23.1.0
Requires-Dist: pyyaml
Requires-Dist: wexample-helpers>=19.1.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Description-Content-Type: text/markdown

# helpers_yaml

Version: 7.0.2

`wexample-helpers-yaml` provides thin wrappers around PyYAML for reading and writing YAML files (`yaml_read`, `yaml_read_dict`, `yaml_write` in src/wexample_helpers_yaml/helper/yaml_helpers.py), plus `yaml_fill_unresolved_vars` which replaces `${VAR}` placeholders in a YAML string before parsing. It also ships `HasYamlEnvKeysFile` (src/wexample_helpers_yaml/classes/mixin/has_yaml_env_keys_file.py), a mixin that loads a YAML file into a class's `env_config` mapping without touching `os.environ`. The package is aimed at Python projects in the wexample suite that need structured YAML I/O or want to drive environment configuration from YAML files.

## Table of Contents

- [Installation](#installation)
- [Quickstart](#quickstart)
- [Tests](#tests)
- [Architecture](#architecture)
- [Integration in the Suite](#integration-in-the-suite)
- [Dependencies](#dependencies)
- [Versioning & Compatibility Policy](#versioning--compatibility-policy)
- [License](#license)
- [About us](#about-us)
- [Known Limitations & Roadmap](#known-limitations--roadmap)
- [Status & Compatibility](#status--compatibility)
- [Useful Links](#useful-links)
- [Migration Notes](#migration-notes)

## Installation

```bash
pip install wexample-helpers-yaml
```

Requires Python >=3.10.

## Quickstart

Install from PyPI:

```bash
pip install wexample-helpers-yaml
```

All functions are in src/wexample_helpers_yaml/helper/yaml_helpers.py.

**Write and read back a YAML file:**

```python
from wexample_helpers_yaml.helper.yaml_helpers import yaml_write, yaml_read_dict

yaml_write("/tmp/config.yml", {"host": "localhost", "port": 5432})

config = yaml_read_dict("/tmp/config.yml")
print(config["host"])  # localhost
```

**Strip unresolved `${VAR}` placeholders before parsing:**

```python
import yaml
from wexample_helpers_yaml.helper.yaml_helpers import yaml_fill_unresolved_vars

raw = "host: ${DB_HOST}\nport: 5432"
data = yaml.safe_load(yaml_fill_unresolved_vars(raw))
print(data)  # {'host': '', 'port': 5432}
```

Pass `fill_value` to substitute something other than an empty string: `yaml_fill_unresolved_vars(raw, fill_value="localhost")`.

## Tests

This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.

### Installation

First, install the required testing dependencies:
```bash
.venv/bin/python -m pip install pytest pytest-cov
```

### Basic Usage

Run all tests with coverage:
```bash
.venv/bin/python -m pytest --cov --cov-report=html
```

### Common Commands
```bash
# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module

# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing

# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html

# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html

# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
```

### Viewing HTML Reports

After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.

### Coverage Threshold

To enforce a minimum coverage percentage:
```bash
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
```

This will cause the test suite to fail if coverage drops below 80%.

## Architecture

The package has three parts: a helper module with all public functions, a mixin class, and a type-alias module. There is no framework layer, no registry, and no configuration at import time.

### Helper module

src/wexample_helpers_yaml/helper/yaml_helpers.py is where every callable lives.

`yaml_read(file_path, default)` opens the file, calls `yaml.safe_load`, and returns the result when it is a `dict`. Any exception — missing file, parse error, wrong type — is caught and the `default` is returned instead.

`yaml_read_dict(file_path, default)` wraps `yaml_read` and guarantees a `dict` return: if `yaml_read` comes back falsy it returns `default or {}`, otherwise it asserts the value is a `dict` and hands it back.

`yaml_write(file_path, content)` opens the file for writing and calls `yaml.safe_dump`.

`yaml_fill_unresolved_vars(yml_text, fill_value)` replaces every `${VAR_NAME}` placeholder in a raw YAML string before it reaches a parser. The regex `_UNRESOLVED_VAR_RE = re.compile(r"\$\{([^}]+)\}")` is compiled once at module import; `fill_value` defaults to an empty string so unset variables silently become blank rather than breaking the parse.

### Call path for file I/O

```
caller
  └─ yaml_read_dict(path)
       └─ yaml_read(path)
            └─ open(path) → yaml.safe_load()
```

`yaml_read_dict` is the preferred entry point. Call `yaml_read` directly only when a non-dict result (e.g. a plain list) is acceptable.

### Call path for placeholder substitution

```
caller
  └─ yaml_fill_unresolved_vars(raw_text, fill_value)
       └─ _UNRESOLVED_VAR_RE.sub(lambda _: fill_str, yml_text)
```

The caller is responsible for feeding the result into `yaml.safe_load` — the function returns a string, not a parsed structure.

### Mixin class

src/wexample_helpers_yaml/classes/mixin/has_yaml_env_keys_file.py defines `HasYamlEnvKeysFile`, which extends `HasEnvKeysFile` from `wexample-helpers`. Its single method `_init_env_file_yaml(file_path)` loads a YAML file into the instance's `env_config` mapping and then calls the inherited `_validate_env_keys()`. It deliberately does not write to `os.environ`; that step is left to callers that need it.

```
HasYamlEnvKeysFile._init_env_file_yaml(file_path)
  └─ yaml_read_dict(file_path)          # helper module
  └─ self.env_config.update(result)
  └─ self._validate_env_keys()          # inherited from HasEnvKeysFile
```

### Type aliases

src/wexample_helpers_yaml/const/types.py re-exports two aliases from `wexample-helpers`:

- `YamlContent` — alias of `StructuredData`, used as the return type of `yaml_read`.
- `YamlContentDict` — alias of `StringKeysDict`, used as the return type of `yaml_read_dict` and the argument type of `yaml_write`.

These aliases exist to give callers a YAML-specific name to import without pulling in the underlying `wexample-helpers` types directly.

## Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

### Related Packages

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.

## Dependencies

- attrs: >=23.1.0
- cattrs: >=23.1.0
- pyyaml: 
- wexample-helpers: >=19.1.0

## Versioning & Compatibility Policy

Wexample packages follow **Semantic Versioning** (SemVer):

- **MAJOR**: Breaking changes
- **MINOR**: New features, backward compatible
- **PATCH**: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

Free to use in both personal and commercial projects.

## About us

[Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

## Known Limitations & Roadmap

Current limitations and planned features are tracked in the GitHub issues.

See the [project roadmap](https://github.com/wexample/python-helpers_yaml/issues) for upcoming features and improvements.

## Status & Compatibility

**Maturity**: Production-ready

**Python Support**: >=3.10

**OS Support**: Linux, macOS, Windows

**Status**: Actively maintained

## Useful Links

- **Homepage**: https://github.com/wexample/python-helpers-yaml
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
- **Issue Tracker**: https://github.com/wexample/python-helpers-yaml/issues
- **Discussions**: https://github.com/wexample/python-helpers-yaml/discussions
- **PyPI**: [pypi.org/project/wexample-helpers-yaml](https://pypi.org/project/wexample-helpers-yaml/)

## Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.
