v6e


Namev6e JSON
Version 0.1.7 PyPI version JSON
download
home_pageNone
SummaryA simple, type-safe, and extensible Python validations framework
upload_time2025-02-23 23:16:08
maintainerNone
docs_urlNone
authorNone
requires_python<3.13,~=3.11
licenseNone
keywords check data validate validation
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 🔍 V6E

[![PyPI version](https://badge.fury.io/py/v6e.svg)](https://badge.fury.io/py/v6e)
[![License](https://img.shields.io/badge/license-MIT-blue)](https://opensource.org/license/mit)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/v6e.svg)](https://pypi.org/project/v6e/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/v6e)](https://pypi.org/project/v6e/)
[![Contributors](https://img.shields.io/github/contributors/danimelchor/v6e)](https://github.com/danimelchor/v6e/graphs/contributors)

A simple, type-safe, and extensible Python validations framework

### Why the name?

`v6e` comes from the [numeronym](https://en.m.wikipedia.org/wiki/Numeronym) of "validate".

### Examples

Check out the examples in `./examples`! You can run them locally with:

```
uv run examples/validations.py
```

## Usage

**Basic validations**
```python
import v6e as v

my_validation = v.int().gte(18).lte(21)

# Use it only to check if the value conforms
my_validation.check(18)  # True
my_validation.check(21)  # True
my_validation.check(54)  # False

# Use `.parse()` to validate and get the parsed value
my_validation.parse(21)  # Ok -> Returns 21 (int)
my_validation.parse("21")  # Ok -> Returns 21 (int)
my_validation.parse(54)  # Err -> Raises a ValidationException
```

**Chaining your validations and transformations**
```python
my_validation = v.str().trim().starts_with("foo").ends_with("foo").regex(r"^[a-z0-9]*$")
my_validation.parse("  foo12")  # Ok -> Returns 'foo12' (str)
my_validation.parse("12foo  ")  # Ok -> Returns '12foo' (str)
my_validation.parse("1foo2")  # Err -> Raises a ValidationException
```

**Handling multiple possible types**
```python
union = v.str().starts_with("foo") | v.int().gte(5)

union.parse("foobar")  # Ok -> Returns 'foobar' (str)
union.parse("1foo2")  # Err -> Raises a ValidationException

union.parse(5)  # Ok -> Returns 5 (int)
union.parse(3)  # Err -> Raises a ValidationException

union.parse(None)  # Err -> Raises a ValidationException
```

**Custom validations**
```python
def _validate_earth_age(x: int) -> None:
    if x != 4_543_000_000:
        raise ValueError("The Earth is 4.543 billion years old. Try 4543000000.")

earth_age = v.int().custom(_validate_earth_age)
earth_age.parse(4_543_000_000)  # Ok -> Returns 4_543_000_000 (int)
earth_age.parse("4543000000")  # Ok -> Returns 4_543_000_000 (int)
earth_age.parse(1)  # Err -> Raises ValidationException
```

**Custom reusable types**
```python
class DivThree(v.IntType):
    @override
    def parse_raw(self, raw: t.Any):
        parsed: int = super().parse_raw(raw)
        if parsed % 3 != 0:
            raise ValueError(f"Woops! {parsed!r} is not divisible by three")


my_validation = DivThree().gt(5)
my_validation.parse(6)  # Ok -> Returns 6
my_validation.parse(3)  # Err (not >5) -> Raises a ValidationException
my_validation.parse(7)  # Err (not div by 3) -> Raises a ValidationException
```

## 🐍 Type-checking

This library is fully type-checked. This means that all types will be correctly inferred
from the arguments you pass in.

In this example your editor will correctly infer the type:
```python
my_validation = v.int().gte(8).lte(4)
t.reveal_type(my_validation)  # Type of "my_validation" is "V6eInt"
t.reveal_type(my_validation.check)  # Type of "my_validation.check" is "(raw: Any) -> bool"
t.reveal_type(my_validation.safe_parse)  # Type of "my_validation" is "(raw: Any) -> V6eResult[int]"
t.reveal_type(my_validation.parse)  # Type of "my_validation" is "(raw: Any) -> int"
```

## Why do I care?

Type checking will help you catch issues way earlier in the development cycle. It will also
provide nice autocomplete features in your editor that will make you faster ⚡.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "v6e",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.13,~=3.11",
    "maintainer_email": null,
    "keywords": "check, data, validate, validation",
    "author": null,
    "author_email": "Daniel Melchor <dmelchor@pm.me>",
    "download_url": "https://files.pythonhosted.org/packages/ae/f8/e0a887e76fede24e9216db373f1cbc12512504f51076fcb5d49545b9b449/v6e-0.1.7.tar.gz",
    "platform": null,
    "description": "# \ud83d\udd0d V6E\n\n[![PyPI version](https://badge.fury.io/py/v6e.svg)](https://badge.fury.io/py/v6e)\n[![License](https://img.shields.io/badge/license-MIT-blue)](https://opensource.org/license/mit)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/v6e.svg)](https://pypi.org/project/v6e/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/v6e)](https://pypi.org/project/v6e/)\n[![Contributors](https://img.shields.io/github/contributors/danimelchor/v6e)](https://github.com/danimelchor/v6e/graphs/contributors)\n\nA simple, type-safe, and extensible Python validations framework\n\n### Why the name?\n\n`v6e` comes from the [numeronym](https://en.m.wikipedia.org/wiki/Numeronym) of \"validate\".\n\n### Examples\n\nCheck out the examples in `./examples`! You can run them locally with:\n\n```\nuv run examples/validations.py\n```\n\n## Usage\n\n**Basic validations**\n```python\nimport v6e as v\n\nmy_validation = v.int().gte(18).lte(21)\n\n# Use it only to check if the value conforms\nmy_validation.check(18)  # True\nmy_validation.check(21)  # True\nmy_validation.check(54)  # False\n\n# Use `.parse()` to validate and get the parsed value\nmy_validation.parse(21)  # Ok -> Returns 21 (int)\nmy_validation.parse(\"21\")  # Ok -> Returns 21 (int)\nmy_validation.parse(54)  # Err -> Raises a ValidationException\n```\n\n**Chaining your validations and transformations**\n```python\nmy_validation = v.str().trim().starts_with(\"foo\").ends_with(\"foo\").regex(r\"^[a-z0-9]*$\")\nmy_validation.parse(\"  foo12\")  # Ok -> Returns 'foo12' (str)\nmy_validation.parse(\"12foo  \")  # Ok -> Returns '12foo' (str)\nmy_validation.parse(\"1foo2\")  # Err -> Raises a ValidationException\n```\n\n**Handling multiple possible types**\n```python\nunion = v.str().starts_with(\"foo\") | v.int().gte(5)\n\nunion.parse(\"foobar\")  # Ok -> Returns 'foobar' (str)\nunion.parse(\"1foo2\")  # Err -> Raises a ValidationException\n\nunion.parse(5)  # Ok -> Returns 5 (int)\nunion.parse(3)  # Err -> Raises a ValidationException\n\nunion.parse(None)  # Err -> Raises a ValidationException\n```\n\n**Custom validations**\n```python\ndef _validate_earth_age(x: int) -> None:\n    if x != 4_543_000_000:\n        raise ValueError(\"The Earth is 4.543 billion years old. Try 4543000000.\")\n\nearth_age = v.int().custom(_validate_earth_age)\nearth_age.parse(4_543_000_000)  # Ok -> Returns 4_543_000_000 (int)\nearth_age.parse(\"4543000000\")  # Ok -> Returns 4_543_000_000 (int)\nearth_age.parse(1)  # Err -> Raises ValidationException\n```\n\n**Custom reusable types**\n```python\nclass DivThree(v.IntType):\n    @override\n    def parse_raw(self, raw: t.Any):\n        parsed: int = super().parse_raw(raw)\n        if parsed % 3 != 0:\n            raise ValueError(f\"Woops! {parsed!r} is not divisible by three\")\n\n\nmy_validation = DivThree().gt(5)\nmy_validation.parse(6)  # Ok -> Returns 6\nmy_validation.parse(3)  # Err (not >5) -> Raises a ValidationException\nmy_validation.parse(7)  # Err (not div by 3) -> Raises a ValidationException\n```\n\n## \ud83d\udc0d Type-checking\n\nThis library is fully type-checked. This means that all types will be correctly inferred\nfrom the arguments you pass in.\n\nIn this example your editor will correctly infer the type:\n```python\nmy_validation = v.int().gte(8).lte(4)\nt.reveal_type(my_validation)  # Type of \"my_validation\" is \"V6eInt\"\nt.reveal_type(my_validation.check)  # Type of \"my_validation.check\" is \"(raw: Any) -> bool\"\nt.reveal_type(my_validation.safe_parse)  # Type of \"my_validation\" is \"(raw: Any) -> V6eResult[int]\"\nt.reveal_type(my_validation.parse)  # Type of \"my_validation\" is \"(raw: Any) -> int\"\n```\n\n## Why do I care?\n\nType checking will help you catch issues way earlier in the development cycle. It will also\nprovide nice autocomplete features in your editor that will make you faster \u26a1.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A simple, type-safe, and extensible Python validations framework",
    "version": "0.1.7",
    "project_urls": {
        "Documentation": "https://github.com/danimelchor/v6e",
        "Homepage": "https://github.com/danimelchor/v6e",
        "Issues": "https://github.com/danimelchor/v6e/issues",
        "Repository": "https://github.com/danimelchor/v6e"
    },
    "split_keywords": [
        "check",
        " data",
        " validate",
        " validation"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a106315076206c5eb804a97ea9c636e8d671c8863fc2113fb94312426504f4c1",
                "md5": "333558b4e8e3569e5a7dd761a121f123",
                "sha256": "e4773ecf31bcccb8c218fdc6a05ab06bbe7fca7f2424f23ce06475f89493150c"
            },
            "downloads": -1,
            "filename": "v6e-0.1.7-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "333558b4e8e3569e5a7dd761a121f123",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.13,~=3.11",
            "size": 9028,
            "upload_time": "2025-02-23T23:16:06",
            "upload_time_iso_8601": "2025-02-23T23:16:06.788318Z",
            "url": "https://files.pythonhosted.org/packages/a1/06/315076206c5eb804a97ea9c636e8d671c8863fc2113fb94312426504f4c1/v6e-0.1.7-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "aef8e0a887e76fede24e9216db373f1cbc12512504f51076fcb5d49545b9b449",
                "md5": "0b54f1fa7c35bf13d6cced1196d27034",
                "sha256": "ee2649273bec26f2cd19c721931d6539f2cdec7e58297c453cf1b620d4fae9bc"
            },
            "downloads": -1,
            "filename": "v6e-0.1.7.tar.gz",
            "has_sig": false,
            "md5_digest": "0b54f1fa7c35bf13d6cced1196d27034",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.13,~=3.11",
            "size": 16443,
            "upload_time": "2025-02-23T23:16:08",
            "upload_time_iso_8601": "2025-02-23T23:16:08.472343Z",
            "url": "https://files.pythonhosted.org/packages/ae/f8/e0a887e76fede24e9216db373f1cbc12512504f51076fcb5d49545b9b449/v6e-0.1.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-02-23 23:16:08",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "danimelchor",
    "github_project": "v6e",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "v6e"
}
        
Elapsed time: 0.48836s