Metadata-Version: 2.4
Name: philiprehberger-env-validator
Version: 0.4.0
Summary: Schema-based environment variable validation with type coercion and helpful error messages.
Project-URL: Homepage, https://github.com/philiprehberger/py-env-validator#readme
Project-URL: Repository, https://github.com/philiprehberger/py-env-validator
Project-URL: Issues, https://github.com/philiprehberger/py-env-validator/issues
Project-URL: Changelog, https://github.com/philiprehberger/py-env-validator/blob/main/CHANGELOG.md
Author: Philip Rehberger
License-Expression: MIT
License-File: LICENSE
Keywords: config,env,environment,schema,validation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# philiprehberger-env-validator

[![Tests](https://github.com/philiprehberger/py-env-validator/actions/workflows/publish.yml/badge.svg)](https://github.com/philiprehberger/py-env-validator/actions/workflows/publish.yml)
[![PyPI version](https://img.shields.io/pypi/v/philiprehberger-env-validator.svg)](https://pypi.org/project/philiprehberger-env-validator/)
[![Last updated](https://img.shields.io/github/last-commit/philiprehberger/py-env-validator)](https://github.com/philiprehberger/py-env-validator/commits/main)

Schema-based environment variable validation with type coercion and helpful error messages.

## Installation

```bash
pip install philiprehberger-env-validator
```

## Usage

### Basic Validation

```python
from philiprehberger_env_validator import Schema, validate

schema = (
    Schema()
    .string("DATABASE_URL", description="PostgreSQL connection string")
    .integer("PORT", default=3000)
    .boolean("DEBUG", default=False)
    .string("NODE_ENV", choices=["development", "staging", "production"])
)

config = validate(schema)
print(config["PORT"])  # 3000 (int, not string)
```

### Field Types

```python
schema = (
    Schema()
    .string("API_KEY")
    .integer("MAX_CONNECTIONS")
    .float_field("RATE_LIMIT")
    .boolean("VERBOSE")
    .url("WEBHOOK_URL")
    .email("ADMIN_EMAIL")
)
```

### Custom Validation

```python
schema = Schema().string(
    "API_KEY",
    pattern=r"^sk-[a-zA-Z0-9]{32}$",
    validator=lambda v: len(v) > 10,
)
```

### Optional Fields

```python
schema = (
    Schema()
    .string("REQUIRED_VAR")
    .string("OPTIONAL_VAR", required=False, default="fallback")
)
```

### Custom Source

```python
config = validate(schema, source={"PORT": "8080", "DEBUG": "true"})
```

### Error Handling

```python
from philiprehberger_env_validator import ValidationError

try:
    config = validate(schema)
except ValidationError as e:
    for error in e.errors:
        print(error)
```

### Schema Documentation

Generate formatted help text documenting all fields, grouped by required and optional.

```python
schema = (
    Schema()
    .url("DATABASE_URL", description="PostgreSQL connection string")
    .string("API_KEY")
    .boolean("DEBUG", default=False, required=False, description="Enable debug mode")
    .integer("PORT", default=8000, required=False)
)

print(schema.generate_help())
# REQUIRED:
#   DATABASE_URL (url): PostgreSQL connection string
#   API_KEY (str): No description
#
# OPTIONAL:
#   DEBUG (bool) [default: false]: Enable debug mode
#   PORT (int) [default: 8000]: No description
```

### Load from .env File

Read and validate a `.env` file directly against a schema.

```python
schema = (
    Schema()
    .string("DATABASE_URL")
    .integer("PORT", default=3000)
    .boolean("DEBUG", default=False)
)

config = schema.load_from_env_file(".env")
print(config["DATABASE_URL"])
print(config["PORT"])  # coerced to int
```

The `.env` file uses standard `KEY=VALUE` format. Comments (`#`) and blank lines are skipped. Quoted values are unquoted automatically.

### List Fields

`list_field()` parses comma-separated values into a list, with optional per-item type coercion.

```python
schema = (
    Schema()
    .list_field("ALLOWED_HOSTS")               # default: split on "," as strings
    .list_field("PORTS", item_type=int)        # coerce each element to int
    .list_field("PATHS", sep=":")              # custom separator
)

config = validate(schema, source={
    "ALLOWED_HOSTS": "a.com, b.com, c.com",
    "PORTS": "80,443,8080",
    "PATHS": "/usr/bin:/usr/local/bin",
})
# {
#   "ALLOWED_HOSTS": ["a.com", "b.com", "c.com"],
#   "PORTS": [80, 443, 8080],
#   "PATHS": ["/usr/bin", "/usr/local/bin"],
# }
```

### JSON values

`json_field()` parses an env var value as JSON, returning the decoded object.

```python
schema = (
    Schema()
    .json_field("FEATURE_FLAGS")
    .json_field("LIMITS", required=False, default={"max": 100})
)

config = validate(schema, source={
    "FEATURE_FLAGS": '{"beta": true, "experimental": false}',
})
# {
#   "FEATURE_FLAGS": {"beta": True, "experimental": False},
#   "LIMITS": {"max": 100},
# }
```

Invalid JSON raises `ValidationError` with a "cannot be converted to json" message.

### Declarative schemas

`Schema.from_dict()` builds a schema from a plain dict — useful when the schema is loaded from YAML/JSON config rather than written in code.

```python
schema = Schema.from_dict({
    "PORT": {"type": "integer", "default": 8080},
    "DEBUG": {"type": "boolean", "default": False},
    "HOSTS": {"type": "list", "sep": ","},
    "FEATURES": {"type": "json", "required": False, "default": {}},
})

config = validate(schema, source={"PORT": "3000", "DEBUG": "true", "HOSTS": "a,b"})
```

Supported `type` values: `"string"`, `"integer"`, `"float"`, `"boolean"`, `"url"`, `"email"`, `"list"`, `"json"`. Remaining keys are forwarded to the corresponding fluent method.

## API

| Function / Class | Description |
|---|---|
| `validate(schema, source)` | Validate environment variables against a schema, returning typed dict |
| `Schema` | Fluent schema builder with `string()`, `integer()`, `float_field()`, `boolean()`, `url()`, `email()`, `list_field()` methods |
| `Schema.list_field(name, *, sep=",", item_type=str)` | Parse a comma-separated list with optional `int`/`float` coercion |
| `Schema.json_field(name, required=True, default=None)` | Parse the env var value as JSON via `json.loads` |
| `Schema.from_dict(spec)` | Build a `Schema` declaratively from a dict mapping field name to kwargs (with a `"type"` key) |
| `Schema.generate_help()` | Return formatted help text documenting all fields grouped by required/optional |
| `Schema.load_from_env_file(path)` | Load and validate a `.env` file against the schema |
| `FieldSpec` | Field specification with type, default, choices, pattern, validator, and description options |
| `ValidationError` | Raised when validation fails, contains list of error messages in `errors` |

## Development

```bash
pip install -e .
python -m pytest tests/ -v
```

## Support

If you find this project useful:

⭐ [Star the repo](https://github.com/philiprehberger/py-env-validator)

🐛 [Report issues](https://github.com/philiprehberger/py-env-validator/issues?q=is%3Aissue+is%3Aopen+label%3Abug)

💡 [Suggest features](https://github.com/philiprehberger/py-env-validator/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)

❤️ [Sponsor development](https://github.com/sponsors/philiprehberger)

🌐 [All Open Source Projects](https://philiprehberger.com/open-source-packages)

💻 [GitHub Profile](https://github.com/philiprehberger)

🔗 [LinkedIn Profile](https://www.linkedin.com/in/philiprehberger)

## License

[MIT](LICENSE)
