Metadata-Version: 2.2
Name: tomlval
Version: 1.0.2
Summary: A simple and easy to use TOML validator for Python.
Author-email: Marcus Fredriksson <marcus@marcusfredriksson.com>
License: MIT License
        
        Copyright (c) 2025 Marcus Fredriksson
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/marcusfrdk/tomlval
Project-URL: Repository, https://github.com/marcusfrdk/tomlval
Project-URL: Issues, https://github.com/marcusfrdk/tomlval/issues
Keywords: toml,validator,validation,parser,python
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: build
Requires-Dist: build; extra == "build"
Requires-Dist: twine; extra == "build"
Provides-Extra: dev
Requires-Dist: black>=24.10.0; extra == "dev"
Requires-Dist: pytest>=8.3.4; extra == "dev"
Requires-Dist: isort>=5.13.2; extra == "dev"
Requires-Dist: pylint>=3.3.2; extra == "dev"
Requires-Dist: pre-commit>=4.0.1; extra == "dev"

# TOML Validator

![top language](https://img.shields.io/github/languages/top/marcusfrdk/tomlval)
![code size](https://img.shields.io/github/languages/code-size/marcusfrdk/tomlval)
![last commit](https://img.shields.io/github/last-commit/marcusfrdk/tomlval)
![issues](https://img.shields.io/github/issues/marcusfrdk/tomlval)
![contributors](https://img.shields.io/github/contributors/marcusfrdk/tomlval)
![PyPI](https://img.shields.io/pypi/v/tomlval)
![License](https://img.shields.io/github/license/marcusfrdk/tomlval)

A simple and easy to use TOML validator for Python.

## Installation

You can install the package from [PyPI](https://pypi.org/project/tomlval/):

```bash
pip install tomlval
```

The package is available for Python 3.11 and newer.

## Concepts

Before using the package, there are some concepts you may need to understand for the most optimal use of the package.

### Key

A key is the name of a field in a TOML file, such as `name`, `person.name`, etc. Keys must conform to the TOML specification, which means keys are either **snake_case** or **SCREAMING_SNAKE_CASE**. For the validator, keys may also include wildcards, such as `*name`, `person.*`, etc.

### Handler

A _handler_ is a function that is called for a certain key. Handlers can be of the following types:

-   Types, such as `int`, `str`, `float`.
-   Tuples/Lists of types, such as `(int, str)`, `[int, str]`.
-   Anonymous functions (`lambda`)
-   Named functions (Callable objects, such as `def my_handler(key, value): ...`)

The following argument configurations are supported:

-   `fn()`
-   `fn(key)`
-   `fn(value)`
-   `fn(key, value)`

If the handler has any other parameters than `key` or `value`, the validator will raise a `TOMLHandlerError`.

Handlers may return any type, but is is recommended to use the return type as an error message if the value is invalid. The validator considers a `None` return value a successful validation.

### Schema

The schema is used to bring give the validator default values. The schema is defined in the `TOMLSchema` class, and is passed to the `TOMLValidator` class. To create a schema, you pass a dictionary with the keys and their respective allowed types.

Here is an example of a schema:

```python
{
    "single_type": str,
    "list_of_strings": [str],
    "mixed_list:" [str, int],
    "multiple_types": (int, float),
    "optional?": str,
    "nested": {
        "key": str
    }
}
```

When a schema is defined, the validator will also check if values are missing and if their types are correct. If a handler is defined for a key, the validator will use the handler instead of the type defined in the schema.

### Validator

The validator is the core of the package. It is used to validate a TOML file. A schema is optionally passed to the validator, and handlers are added using the `add_handler` method. Once you feel ready, you can call the `validate` method to get a dictionary of errors.

Currently, there are two type of error structures, for type errors and all other errors.

Type errors are structured as follows:

```python
"key": (message, (value, expected_type, actual_type))
```

_`expected_type` and `actual_type` can be either `type` or `tuple[type]`_

All other errors have a slightly simpler structure:

```python
"key": (message, value)
```

The point of the validator is to parse the data and get the errors in a clean and easy way. **What you do with the errors is up to you.**

## Example

Here is a full example of how to use the validator.

```python
import pathlib
import tomllib
import datetime
from tomlval import TOMLValidator, TOMLSchema

# Load data
path = pathlib.Path("data.toml")

with path.open("rb") as file:
    data = tomllib.load(file)

# Define schema (optional)
structure = {
    "first_name": str,
    "last_name": str,
    "age": int,
    "email": str,
    "phone": str,
    "birthday": datetime.datetime,
    "address": {
        "street": str,
        "city": str,
        "zip": int
    }
}

schema = TOMLSchema(structure) # If the struture is invalid, a TOMLSchemaError is raised

# Define validator
validator = TOMLValidator(data, schema)

# Add handlers
validator.add_handler("*_name", lambda key: None if key in ["first_name", "last_name"] else "invalid-key")
validator.add_handler("age", lambda value: None if 18 < value < 100 else "invalid-age")
validator.add_handler("*", lambda: "invalid-key")

# Validate the data
errors = validator.validate()
```

## Future Plans

Future plans are found in the [TODO](TODO.md) file.

## License

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