Name | v6e JSON |
Version |
0.1.7
JSON |
| download |
home_page | None |
Summary | A simple, type-safe, and extensible Python validations framework |
upload_time | 2025-02-23 23:16:08 |
maintainer | None |
docs_url | None |
author | None |
requires_python | <3.13,~=3.11 |
license | None |
keywords |
check
data
validate
validation
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# 🔍 V6E
[](https://badge.fury.io/py/v6e)
[](https://opensource.org/license/mit)
[](https://pypi.org/project/v6e/)
[](https://pypi.org/project/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[](https://badge.fury.io/py/v6e)\n[](https://opensource.org/license/mit)\n[](https://pypi.org/project/v6e/)\n[](https://pypi.org/project/v6e/)\n[](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"
}