valdec


Namevaldec JSON
Version 1.1.0 PyPI version JSON
download
home_pagehttps://github.com/EvgeniyBurdin/valdec
SummaryDecorator for validating function arguments and result.
upload_time2021-02-03 16:48:32
maintainer
docs_urlNone
authorEvgeniy Burdin
requires_python>=3.7
licenseMIT
keywords validation function
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI
coveralls test coverage
            # valdec

[![PyPI](https://img.shields.io/pypi/v/valdec)](https://pypi.org/project/valdec) [![Build Status](https://travis-ci.com/EvgeniyBurdin/valdec.svg?branch=main)](https://travis-ci.com/EvgeniyBurdin/valdec) [![Coverage Status](https://coveralls.io/repos/github/EvgeniyBurdin/valdec/badge.svg?branch=main)](https://coveralls.io/github/EvgeniyBurdin/valdec?branch=main) [![Total alerts](https://img.shields.io/lgtm/alerts/g/EvgeniyBurdin/valdec.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/EvgeniyBurdin/valdec/alerts/) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/EvgeniyBurdin/valdec.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/EvgeniyBurdin/valdec/context:python) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/valdec)

Decorator for validating arguments and/or result of functions and methods of a class against annotations.

Can be used in synchronous or asynchronous version.

Validation is supported using [pydantic.BaseModel](https://github.com/samuelcolvin/pydantic) and [validated_dc.ValidatedDC](https://github.com/EvgeniyBurdin/validated_dc).

You can easily add support for any other validator. To do this, you need to write your own validator-function and specify it in the settings for decorator (how to do this - see the examples below).

*Note: if the result of the function has no annotation, the result is expected to be `None`.*

## Installation

```bash
pip install valdec
```

## Quick example

### Default

Based on the validator `pydantic.BaseModel`:

```bash
pip install pydantic
```

```python
from typing import List, Optional

from pydantic import BaseModel, StrictInt, StrictStr
from valdec.decorators import validate
# from valdec.decorators import async_validate  # Use for async functions


@validate  # all arguments with annotations and return
def func(i: StrictInt, s: StrictStr) -> StrictInt:
    return i

assert func(1, "s") == 1


@validate("i", exclude=True)  # exclude "i" (only "s" and return)
def func(i: StrictInt, s: StrictStr) -> StrictInt:
    return int(i)

assert func("1", "s") == 1


# For example, an Api got a json-string and decoded it:
data_for_group = [
    {"name": "Peter", "profile": {"age": 22, "city": "Samara"}},
    {"name": "Elena", "profile": {"age": 20, "city": "Kazan"}},
]

class Profile(BaseModel):
    age: StrictInt
    city: StrictStr

class Student(BaseModel):
    name: StrictStr
    profile: Profile

@validate("s", "group")  # only "s" and "group"
def func(i: StrictInt, s: StrictStr, group: Optional[List[Student]] = None):

    assert i == "i not int"  # because "i" is not validated
    assert isinstance(s, str)
    for student in group:
        # `student` is now an instance of `Student`
        # (This conversion can be disabled!)
        assert isinstance(student, Student)
        assert isinstance(student.name, str)
        assert isinstance(student.profile.age, int)

    return group

result = func("i not int", "string",  data_for_group)
# The result can be any, because it is not validated.., now this is a list:
assert isinstance(result, list)
```

### validated_dc_validator

It is possible to enable validation with [validated_dc.ValidatedDC](https://github.com/EvgeniyBurdin/validated_dc). To do this, change the reference to the validator-function in the decorator settings:

```bash
pip install validated-dc
```

```python
from dataclasses import dataclass
from typing import List, Optional

from valdec.data_classes import Settings
from valdec.decorators import validate as _validate
from valdec.validator_validated_dc import validator 
from validated_dc import ValidatedDC

custom_settings = Settings(
    validator=validator,     # function for validation
    is_replace_args=True,    # default
    is_replace_result=True,  # default
    extra={}                 # default
)
def validate(*args, **kwargs):  # define new decorator
    kwargs["settings"] = custom_settings
    return _validate(*args, **kwargs)


# The new decorator can now be used:

@validate  # all arguments with annotations and return
def func(i: int, s: str) -> int:
    return i

assert func(1, "s") == 1


@validate("s")  # only "s"
def func(i: int, s: str) -> int:
    return i

assert func("not int", "s") == "not int"


@validate("s", "return")  # only "s" and return
def func(i: int, s: str) -> int:
    return int(i)

assert func("1", "s") == 1


@validate("i", exclude=True)  # exclude "i" (only "s" and return)
def func(i: int, s: str) -> int:
    return int(i)

assert func("1", "s") == 1


data_for_group = [
    {"name": "Peter", "profile": {"age": 22, "city": "Samara"}},
    {"name": "Elena", "profile": {"age": 20, "city": "Kazan"}},
]

@dataclass
class Profile(ValidatedDC):
    age: int
    city: str

@dataclass
class Student(ValidatedDC):
    name: str
    profile: Profile

@validate("s", "group")  # only "s" and "group"
def func(i: int, s: str, group: Optional[List[Student]] = None):

    assert i == "i not int"  # because "i" is not validated
    assert isinstance(s, str)
    for student in group:
        # `student` is now an instance of `Student`
        # (This behavior can be changed by is_replace_args=False in the
        # Settings instance)
        assert isinstance(student, Student)
        assert isinstance(student.name, str)
        assert isinstance(student.profile.age, int)

    return group

result = func("i not int", "string",  data_for_group)
# The result can be any, because it is not validated.., now this is a list:
assert isinstance(result, list)
```

### Errors

`ValidationArgumentsError` is raised on an arguments validation error, and a `ValidationReturnError` on a result validation error:  

```python
from typing import Optional

from pydantic import StrictInt, StrictStr
from valdec.decorators import validate
from valdec.errors import ValidationArgumentsError, ValidationReturnError


class Foo:

    @validate  # all arguments with annotations and return
    def bar_1(self, i: StrictInt, s: Optional[StrictStr] = None):
        pass

    @validate("return")  # only "return"
    def bar_2(self, i: StrictInt, s: Optional[StrictStr] = None):
        return i


foo = Foo()

foo.bar_1(1, "2")  # ok

try:
    foo.bar_1(1, 2)
except ValidationArgumentsError as error:
    print(type(error), error, "\n")


foo.bar_2(None, 1)  # ok

try:
    foo.bar_2(1, 2)
except ValidationReturnError as error:
    print(type(error), error)
```



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/EvgeniyBurdin/valdec",
    "name": "valdec",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "validation function",
    "author": "Evgeniy Burdin",
    "author_email": "e.s.burdin@mail.ru",
    "download_url": "https://files.pythonhosted.org/packages/67/76/ee4414475d712c781d76fad49accece76fd77dc57385502b6864f3f68e6a/valdec-1.1.0.tar.gz",
    "platform": "",
    "description": "# valdec\n\n[![PyPI](https://img.shields.io/pypi/v/valdec)](https://pypi.org/project/valdec) [![Build Status](https://travis-ci.com/EvgeniyBurdin/valdec.svg?branch=main)](https://travis-ci.com/EvgeniyBurdin/valdec) [![Coverage Status](https://coveralls.io/repos/github/EvgeniyBurdin/valdec/badge.svg?branch=main)](https://coveralls.io/github/EvgeniyBurdin/valdec?branch=main) [![Total alerts](https://img.shields.io/lgtm/alerts/g/EvgeniyBurdin/valdec.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/EvgeniyBurdin/valdec/alerts/) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/EvgeniyBurdin/valdec.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/EvgeniyBurdin/valdec/context:python) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/valdec)\n\nDecorator for validating arguments and/or result of functions and methods of a class against annotations.\n\nCan be used in synchronous or asynchronous version.\n\nValidation is supported using [pydantic.BaseModel](https://github.com/samuelcolvin/pydantic) and [validated_dc.ValidatedDC](https://github.com/EvgeniyBurdin/validated_dc).\n\nYou can easily add support for any other validator. To do this, you need to write your own validator-function and specify it in the settings for decorator (how to do this - see the examples below).\n\n*Note: if the result of the function has no annotation, the result is expected to be `None`.*\n\n## Installation\n\n```bash\npip install valdec\n```\n\n## Quick example\n\n### Default\n\nBased on the validator `pydantic.BaseModel`:\n\n```bash\npip install pydantic\n```\n\n```python\nfrom typing import List, Optional\n\nfrom pydantic import BaseModel, StrictInt, StrictStr\nfrom valdec.decorators import validate\n# from valdec.decorators import async_validate  # Use for async functions\n\n\n@validate  # all arguments with annotations and return\ndef func(i: StrictInt, s: StrictStr) -> StrictInt:\n    return i\n\nassert func(1, \"s\") == 1\n\n\n@validate(\"i\", exclude=True)  # exclude \"i\" (only \"s\" and return)\ndef func(i: StrictInt, s: StrictStr) -> StrictInt:\n    return int(i)\n\nassert func(\"1\", \"s\") == 1\n\n\n# For example, an Api got a json-string and decoded it:\ndata_for_group = [\n    {\"name\": \"Peter\", \"profile\": {\"age\": 22, \"city\": \"Samara\"}},\n    {\"name\": \"Elena\", \"profile\": {\"age\": 20, \"city\": \"Kazan\"}},\n]\n\nclass Profile(BaseModel):\n    age: StrictInt\n    city: StrictStr\n\nclass Student(BaseModel):\n    name: StrictStr\n    profile: Profile\n\n@validate(\"s\", \"group\")  # only \"s\" and \"group\"\ndef func(i: StrictInt, s: StrictStr, group: Optional[List[Student]] = None):\n\n    assert i == \"i not int\"  # because \"i\" is not validated\n    assert isinstance(s, str)\n    for student in group:\n        # `student` is now an instance of `Student`\n        # (This conversion can be disabled!)\n        assert isinstance(student, Student)\n        assert isinstance(student.name, str)\n        assert isinstance(student.profile.age, int)\n\n    return group\n\nresult = func(\"i not int\", \"string\",  data_for_group)\n# The result can be any, because it is not validated.., now this is a list:\nassert isinstance(result, list)\n```\n\n### validated_dc_validator\n\nIt is possible to enable validation with [validated_dc.ValidatedDC](https://github.com/EvgeniyBurdin/validated_dc). To do this, change the reference to the validator-function in the decorator settings:\n\n```bash\npip install validated-dc\n```\n\n```python\nfrom dataclasses import dataclass\nfrom typing import List, Optional\n\nfrom valdec.data_classes import Settings\nfrom valdec.decorators import validate as _validate\nfrom valdec.validator_validated_dc import validator \nfrom validated_dc import ValidatedDC\n\ncustom_settings = Settings(\n    validator=validator,     # function for validation\n    is_replace_args=True,    # default\n    is_replace_result=True,  # default\n    extra={}                 # default\n)\ndef validate(*args, **kwargs):  # define new decorator\n    kwargs[\"settings\"] = custom_settings\n    return _validate(*args, **kwargs)\n\n\n# The new decorator can now be used:\n\n@validate  # all arguments with annotations and return\ndef func(i: int, s: str) -> int:\n    return i\n\nassert func(1, \"s\") == 1\n\n\n@validate(\"s\")  # only \"s\"\ndef func(i: int, s: str) -> int:\n    return i\n\nassert func(\"not int\", \"s\") == \"not int\"\n\n\n@validate(\"s\", \"return\")  # only \"s\" and return\ndef func(i: int, s: str) -> int:\n    return int(i)\n\nassert func(\"1\", \"s\") == 1\n\n\n@validate(\"i\", exclude=True)  # exclude \"i\" (only \"s\" and return)\ndef func(i: int, s: str) -> int:\n    return int(i)\n\nassert func(\"1\", \"s\") == 1\n\n\ndata_for_group = [\n    {\"name\": \"Peter\", \"profile\": {\"age\": 22, \"city\": \"Samara\"}},\n    {\"name\": \"Elena\", \"profile\": {\"age\": 20, \"city\": \"Kazan\"}},\n]\n\n@dataclass\nclass Profile(ValidatedDC):\n    age: int\n    city: str\n\n@dataclass\nclass Student(ValidatedDC):\n    name: str\n    profile: Profile\n\n@validate(\"s\", \"group\")  # only \"s\" and \"group\"\ndef func(i: int, s: str, group: Optional[List[Student]] = None):\n\n    assert i == \"i not int\"  # because \"i\" is not validated\n    assert isinstance(s, str)\n    for student in group:\n        # `student` is now an instance of `Student`\n        # (This behavior can be changed by is_replace_args=False in the\n        # Settings instance)\n        assert isinstance(student, Student)\n        assert isinstance(student.name, str)\n        assert isinstance(student.profile.age, int)\n\n    return group\n\nresult = func(\"i not int\", \"string\",  data_for_group)\n# The result can be any, because it is not validated.., now this is a list:\nassert isinstance(result, list)\n```\n\n### Errors\n\n`ValidationArgumentsError` is raised on an arguments validation error, and a `ValidationReturnError` on a result validation error:  \n\n```python\nfrom typing import Optional\n\nfrom pydantic import StrictInt, StrictStr\nfrom valdec.decorators import validate\nfrom valdec.errors import ValidationArgumentsError, ValidationReturnError\n\n\nclass Foo:\n\n    @validate  # all arguments with annotations and return\n    def bar_1(self, i: StrictInt, s: Optional[StrictStr] = None):\n        pass\n\n    @validate(\"return\")  # only \"return\"\n    def bar_2(self, i: StrictInt, s: Optional[StrictStr] = None):\n        return i\n\n\nfoo = Foo()\n\nfoo.bar_1(1, \"2\")  # ok\n\ntry:\n    foo.bar_1(1, 2)\nexcept ValidationArgumentsError as error:\n    print(type(error), error, \"\\n\")\n\n\nfoo.bar_2(None, 1)  # ok\n\ntry:\n    foo.bar_2(1, 2)\nexcept ValidationReturnError as error:\n    print(type(error), error)\n```\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Decorator for validating function arguments and result.",
    "version": "1.1.0",
    "project_urls": {
        "Homepage": "https://github.com/EvgeniyBurdin/valdec"
    },
    "split_keywords": [
        "validation",
        "function"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4f4bffc694d25a2079bc2f7765f5b94a95f72c772ae5d9e1ae025cfc8205bfc0",
                "md5": "5416917c56a8f7ae046632b6339566ae",
                "sha256": "d252ec0d0a841a26d897915cd06d98f962acdba2acb6d8ccc0b9b90ab008f566"
            },
            "downloads": -1,
            "filename": "valdec-1.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5416917c56a8f7ae046632b6339566ae",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 12132,
            "upload_time": "2021-02-03T16:48:30",
            "upload_time_iso_8601": "2021-02-03T16:48:30.892960Z",
            "url": "https://files.pythonhosted.org/packages/4f/4b/ffc694d25a2079bc2f7765f5b94a95f72c772ae5d9e1ae025cfc8205bfc0/valdec-1.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6776ee4414475d712c781d76fad49accece76fd77dc57385502b6864f3f68e6a",
                "md5": "7ed8ba6b8df2931606bd97bf4b368bf2",
                "sha256": "bc8570e62a148ff81e5061916b7cc22af64d1524dad8c78873edc092e4a114a1"
            },
            "downloads": -1,
            "filename": "valdec-1.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "7ed8ba6b8df2931606bd97bf4b368bf2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 10895,
            "upload_time": "2021-02-03T16:48:32",
            "upload_time_iso_8601": "2021-02-03T16:48:32.554185Z",
            "url": "https://files.pythonhosted.org/packages/67/76/ee4414475d712c781d76fad49accece76fd77dc57385502b6864f3f68e6a/valdec-1.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2021-02-03 16:48:32",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "EvgeniyBurdin",
    "github_project": "valdec",
    "travis_ci": true,
    "coveralls": true,
    "github_actions": false,
    "requirements": [],
    "lcname": "valdec"
}
        
Elapsed time: 0.73114s