Metadata-Version: 2.1
Name: pydantic_yaml
Version: 0.11.2
Summary: Adds some YAML functionality to the excellent `pydantic` library.
Author-email: NowanIlfideme <git@nowan.dev>
License: MIT License
        
        Copyright (c) 2020 Anatoly Makarevich
        
        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: github, https://github.com/NowanIlfideme/pydantic-yaml
Project-URL: docs, https://pydantic-yaml.readthedocs.io/en/latest/
Keywords: pydantic,yaml
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Software Development
Classifier: Typing :: Typed
Classifier: Operating System :: OS Independent
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Provides-Extra: dev
Provides-Extra: docs
Provides-Extra: pyyaml
Provides-Extra: ruamel
Provides-Extra: semver
License-File: LICENSE

# pydantic-yaml

[![PyPI version](https://badge.fury.io/py/pydantic-yaml.svg)](https://badge.fury.io/py/pydantic-yaml) [![Documentation Status](https://readthedocs.org/projects/pydantic-yaml/badge/?version=latest)](https://pydantic-yaml.readthedocs.io/en/latest/?badge=latest)
 [![Unit Tests](https://github.com/NowanIlfideme/pydantic-yaml/actions/workflows/python-testing.yml/badge.svg)](https://github.com/NowanIlfideme/pydantic-yaml/actions/workflows/python-testing.yml)

This is a small helper library that adds some YAML capabilities to [pydantic](https://github.com/samuelcolvin/pydantic), namely dumping to yaml via the `yaml_model.yaml()` function, and parsing from strings/files using `YamlModel.parse_raw()` and `YamlModel.parse_file()`. It also adds `Enum` subclasses that get dumped to YAML as strings or integers, and fixes dumping of some typical types.

[Documentation on ReadTheDocs.org](https://pydantic-yaml.readthedocs.io/en/latest/)

## Basic Usage

Typical usage is seen below. See the [pydantic docs](https://pydantic-docs.helpmanual.io/)
for more usage examples.

```python
from pydantic import BaseModel, validator
from pydantic_yaml import YamlStrEnum, YamlModel


class MyEnum(YamlStrEnum):
    """This is a custom enumeration that is YAML-safe."""

    a = "a"
    b = "b"

class InnerModel(BaseModel):
    """This is a normal pydantic model that can be used as an inner class."""

    fld: float = 1.0

class MyModel(YamlModel):
    """This is our custom class, with a `.yaml()` method.

    The `parse_raw()` and `parse_file()` methods are also updated to be able to
    handle `content_type='application/yaml'`, `protocol="yaml"` and file names
    ending with `.yml`/`.yaml`
    """

    x: int = 1
    e: MyEnum = MyEnum.a
    m: InnerModel = InnerModel()

    @validator('x')
    def _chk_x(cls, v: int) -> int:  # noqa
        """You can add your normal pydantic validators, like this one."""
        assert v > 0
        return v

m1 = MyModel(x=2, e="b", m=InnerModel(fld=1.5))

# This dumps to YAML and JSON respectively
yml = m1.yaml()
jsn = m1.json()

m2 = MyModel.parse_raw(yml)  # This automatically assumes YAML
assert m1 == m2

m3 = MyModel.parse_raw(jsn)  # This will fallback to JSON
assert m1 == m3

m4 = MyModel.parse_raw(yml, proto="yaml")
assert m1 == m4

m5 = MyModel.parse_raw(yml, content_type="application/yaml")
assert m1 == m5
```

## Installation

`pip install pydantic_yaml`

Make sure to install `ruamel.yaml` or `pyyaml` as well. These are optional dependencies:

`pip install pydantic_yaml[ruamel]`

`pip install pydantic_yaml[pyyaml]`

## Mixin Class

Version 0.5.0 adds a `YamlModelMixin` which can be used to add YAML functionality on
top of, or alongside, other base classes:

```python
from typing import List

from pydantic import BaseModel
from pydantic_yaml import YamlModelMixin


class MyBase(BaseModel):
    """This is a normal."""
    x: str = "x"

class ExtModel(YamlModelMixin, MyBase):
    """This model can be sent to/read from YAML."""
    y: List[int] = [1, 2, 3]  # and you can define additional fields, if you want
```

Note that this `YamlModelMixin` must be **before** any `BaseModel`-derived classes.
This will hopefully be resolved in Pydantic 2.0
(see [this discussion](https://github.com/samuelcolvin/pydantic/discussions/3025)
for more details). If you know a better way of implementing this, please make raise
an issue or create a PR!

## Configuration

You can configure the function used to dump and load the YAML by using the `Config`
inner class, [as in Pydantic](https://pydantic-docs.helpmanual.io/usage/model_config/):

```python
class MyModel(YamlModel):
    # ...
    class Config:
        # You can override these fields:
        yaml_dumps = my_custom_dumper
        yaml_loads = lambda x: MyModel()
        # As well as other Pydantic configuration:
        allow_mutation = False
```

## Versioned Models

Since YAML is often used for config files, there is also a `SemVer` str-like class and `VersionedYamlModel` base class.

The `version` attribute is parsed according to the SemVer
([Semantic Versioning](https://semver.org/)) specification.
It's constrained between the `min_version` and `max_version` specified by your models'
`Config` inner class (similar to regular `pydantic` models).

### Usage example

```python
from pydantic import ValidationError
from pydantic_yaml import SemVer, VersionedYamlModel

class A(VersionedYamlModel):
    """Model with min, max constraints as None."""

    foo: str = "bar"


class B(VersionedYamlModel):
    """Model with a maximum version set."""

    foo: str = "bar"

    class Config:
        min_version = "2.0.0"

ex_yml = """
version: 1.0.0
foo: baz
"""

a = A.parse_raw(ex_yml)
assert a.version == SemVer("1.0.0")
assert a.foo == "baz"

try:
    B.parse_raw(ex_yml)
except ValidationError as e:
    print("Correctly got ValidationError:", e, sep="\n")
```
