jsonvv


Namejsonvv JSON
Version 0.2.2 PyPI version JSON
download
home_pagehttps://github.com/daijro/camoufox/tree/main/pythonlib/jsonvv
SummaryJSON value validator
upload_time2024-11-28 04:57:51
maintainerNone
docs_urlNone
authordaijro
requires_python<4.0,>=3.8
licenseMIT
keywords json validator validation typing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # JSONvv

JSON value validator

## Overview

This is a simple JSON schema validator library. It was created for Camoufox to validate passed user configurations. Because I found it useful for other projects, I decided to extract it into a separate library.

JSONvv's syntax parser is written in pure Python. It does not rely on any dependencies.

### Example

<table>
<tr>
<th width="50%">Configuration</th>
<th width="50%">Validator</th>
</tr>
<tr>
<td width="50%">

```python
config = {
    "username": "johndoe",
    "email": "johndoe@example.com",
    "age": 30,
    "chat": "Hello world!",
    "preferences": {
        "notifications": True,
        "theme": "dark"
    },
    "allowed_commands": [
        "/help", "/time", "/weather"
    ],
    "location": [40.7128, -74.0060],
    "hobbies": [
        {
            "name": "Traveling",
            "cities": ["Paris", "London"]
        },
        {
            "name": "reading",
            "hours": {
                "Sunday": 2,
                "Monday": 3,
            }
        }
    ]
}
```

</td>
<td width="50%">

```python
validator = {
    "username": "str",  # Basic username
    "email": "str[/\S+@\S+\.\S+/]",  # Validate emails
    "age": "int[>=18]",  # Age must be 18 or older
    "chat": "str | nil",  # Optional chat message
    "preferences": {
        "notifications": "bool",
        "theme": "str[light, dark] | nil",  # Optional theme
    },
    # Commands must start with "/", but not contain "sudo"
    "allowed_commands": "array[str[/^//] - str[/sudo/]]",
    # Validate coordinate ranges
    "location": "tuple[double[-90 - 90], double[-180 - 180]]",
    # Handle an array of hobby types
    "hobbies": "array[@traveling | @other, >=1]",
    "@traveling": {
        # Require 1 or more cities/countries iff name is "Traveling"
        "*name,type": "str[Traveling]",
        "*cities,countries": "array[str[A-Za-z*], >=1]",
    },
    "@other": {
        "name,type": "str - str[Traveling]",  # Non-traveling types
        # If hour(s) is specified, require days have >0 hours
        "/hours?/": {
            "*/day$/": "int[>0]"
        }
    }
}
```

</td>
</tr>
</table>

<hr width=50>

Then, validate the configuration like this:

```python
from jsonvv import JsonValidator, JvvRuntimeException

val = JsonValidator(validator)
try:
   val.validate(config)
except JvvRuntimeException as exc:
   print("Failed:", exc)
else:
   print('Config is valid!')
```

---

## Table of Contents

- [Key Syntax](#key-syntax)
  - [Regex patterns](#regex-patterns)
  - [Lists of possible values](#lists-of-possible-values)
  - [Required fields (`*`)](#required-fields-)
  - [Grouping keys (`$`)](#grouping-keys-)
- [Supported Types](#supported-types)
  - [String (`str`)](#string-str)
  - [Integer (`int`)](#integer-int)
  - [Double (`double`)](#double-double)
  - [Boolean (`bool`)](#boolean-bool)
  - [Array (`array`)](#array-array)
  - [Tuple (`tuple`)](#tuple-tuple)
  - [Nested Dictionaries](#nested-dictionaries)
  - [Nil (`nil`)](#nil-nil)
  - [Any (`any`)](#any-any)
  - [Required fields (`*`)](#required-fields-)
  - [Type References (`@`)](#type-references-)
- [Advanced Features](#advanced-features)
  - [Subtracting Domains (`-`)](#subtracting-domains--)
  - [Union Types (`|`)](#union-types-)
  - [Conditional Ranges and Values](#conditional-ranges-and-values)
- [Error Handling](#error-handling)

---

## Keys Syntax

Dictionary keys can be specified in several possible ways:

- `"key": "type"`
- `"key1,key2,key3": "type"`
- `"/key\d+/": "type"`
- `"*required_key": "type"`

### Regex patterns

To use regex in a key, wrap it in `/ ... /`.

**Syntax:**

```python
"/key\d+/": "type"
```

### Lists of possible values

To specify a list of keys, use a comma-separated string.

**Syntax:**

```python
"key1,key2,key3": "type"
"/k[ey]{2}1/,key2": "type"
```

To escape a comma, use `!`.

### Required fields (`*`)

Fields marked with `*` are required. The validation will fail without them.

**Syntax:**

```python
"*key1": "type"
"*/key\d+/": "type"
```

### Grouping keys (`$`)

Fields that end with `$group_name` are grouped together. If one of the keys is set, all of the keys in the group must also be set as well.

**Syntax:**

```python
"isEnabled$group1": "bool"
"value$group1": "int[>0]"
```

This will require both `value` is set if and only if `isEnabled` is set.

Multiple `$` can be used to create more complex group dependencies.

---

## Supported Types

### String (`str`)

Represents a string value. Optionally, you can specify a regex pattern that the string must match.

**Syntax:**

- Basic string: `"str"`
- With regex pattern: `"str[regex_pattern]"`
- The escape character for regex is `\`, and for commas is `_`.

**Arguments:**

- `regex_pattern`: A regular expression that the string must match. If not specified, any string is accepted.

**Examples:**

1. Basic string:

   ```python
   "username": "str"
   ```

   Accepts any string value for the key `username`.

2. String with regex pattern:

   ```python
   "fullname": "str[/[A-Z][a-z]+ [A-Z][a-z]+/]"
   ```

   Accepts a string that matches the pattern of a first and last name starting with uppercase letters.

### Integer (`int`)

Represents an integer value. You can specify conditions like exact values, ranges, and inequalities.

**Syntax:**

- Basic integer: `"int"`
- With conditions: `"int[conditions]"`

**Arguments:**

- `conditions`: A comma-separated list of conditions.

**Condition Operators:**

- `==`: Equal to a specific value.
- `>=`: Greater than or equal to a value.
- `<=`: Less than or equal to a value.
- `>`: Greater than a value.
- `<`: Less than a value.
- `range`: A range between two values (inclusive).

**Examples:**

1. Basic integer:

   ```python
   "age": "int"
   ```

   Accepts any integer value for the key `age`.

2. Integer with conditions:

   ```python
   "userage": "int[>=0, <=120]"
   ```

   Accepts integer values between 0 and 120 inclusive.

3. Specific values and ranges

   ```python
   "rating": "int[1-5]"
   "rating": "int[1,2,3,4-5]"
   ```

   Accepts integer values 1, 2, 3, 4, or 5.

4. Ranges with negative numbers:

   ```python
   "rating": "int[-100 - -90]"
   ```

   Accepts integer values from -100 to -90.

### Double (`double`)

Represents a floating-point number. Supports the same conditions as integers.

**Syntax:**

- Basic double: `"double"`
- With conditions: `"double[conditions]"`

**Arguments:**

- `conditions`: A comma-separated list of conditions.

**Examples:**

1. Basic double:

   ```python
   "price": "double"
   ```

   Accepts any floating-point number for the key `price`.

2. Double with conditions:

   ```python
   "percentage": "double[>=0.0,<=100.0]"
   ```

   Accepts double values between 0.0 and 100.0 inclusive.

### Boolean (`bool`)

Represents a boolean value (`True` or `False`).

**Syntax:**

```python
"isActive": "bool"
```

Accepts a boolean value for the key `isActive`.

### Array (`array`)

Represents a list of elements of a specified type. You can specify conditions on the length of the array.

**Syntax:**

- Basic array: `"array[element_type]"`
- With length conditions: `"array[element_type,length_conditions]"`

**Arguments:**

- `element_type`: The type of the elements in the array.
- `length_conditions`: Conditions on the array length (same as integer conditions).

**Examples:**

1. Basic array:

   ```python
   "tags": "array[str]"
   ```

   Accepts a list of strings for the key `tags`.

2. Array with length conditions:

   ```python
   "scores": "array[int[>=0,<=100],>=1,<=5]"
   ```

   Accepts a list of 1 to 5 integers between 0 and 100 inclusive.

3. Fixed-length array:

   ```python
   "coordinates": "array[double, 2]"
   ```

   Accepts a list of exactly 2 double values.

4. More complex restraints:
   ```python
   "coordinates": "array[array[int[>0]] - tuple[1, 1]], 2]"
   ```

### Tuple (`tuple`)

Represents a fixed-size sequence of elements of specified types.

**Syntax:**

```python
"tuple[element_type1, element_type2]"
```

**Arguments:**

- `element_typeN`: The type of the Nth element in the tuple.

**Examples:**

1. Basic tuple:

   ```python
   "point": "tuple[int, int]"
   ```

   Accepts a tuple or list of two integers.

2. Tuple with mixed types:

   ```python
   "userInfo": "tuple[str, int, bool]"
   ```

   Accepts a tuple of a string, an integer, and a boolean.

### Nested Dictionaries

Represents a nested dictionary structure. Dictionaries are defined using Python's dictionary syntax `{}` in the type definitions.

**Syntax:**

```python
"settings": {
    "volume": "int[>=0,<=100]",
    "brightness": "int[>=0,<=100]",
    "mode": "str"
}
```

**Usage:**

- Define the expected keys and their types within the dictionary.
- You can use all the supported types for the values.

**Examples:**

1. Nested dictionary:

   ```python
   "user": {
       "name": "str",
       "age": "int[>=0]",
       "preferences": {
           "theme": "str",
           "notifications": "bool"
       }
   }
   ```

   Defines a nested dictionary structure for the key `user`.

### Nil (`nil`)

Represents a `None` value.

**Syntax:**

```python
"optionalValue": "int | nil"
```

**Usage:**

- Use `nil` to allow a value to be `None`.
- Often used with union types to specify optional values.

### Any (`any`)

Represents any value.

**Syntax:**

```python
"metadata": "any"
```

**Usage:**

- Use `any` when any value is acceptable.
- Useful for keys where the value is not constrained.

### Type References (`@`)

Allows you to define reusable types and reference them.

**Syntax:**

- Define a named type:

  ```python
  "@typeName": "type_definition"
  ```

- Reference a named type:

  ```python
  "key": "@typeName"
  ```

**Examples:**

1. Defining and using a named type:

   ```python
   "@positiveInt": "int[>0]"
   "userId": "@positiveInt"
   ```

   Defines a reusable type `@positiveInt` and uses it for the key `userId`.

---

## Advanced Features

### Subtracting Domains (`-`)

Allows you to specify that a value should not match a certain type or condition.

**Syntax:**

```python
"typeA - typeB"
```

**Usage:**

- The value must match `typeA` but not `typeB`.

**Examples:**

1. Excluding certain strings:

   ```python
   "message": "str - str[.*error.*]"
   ```

   Accepts any string that does not match the regex pattern `.*error.*`.

2. Excluding a range of numbers:

   ```python
   "score": "int[0-100] - int[>=90]"
   ```

   Accepts integers between 0 and 100, excluding values greater than or equal to 90.

3. Excluding multiple types:

   ```python
   "score": "int[>0,<100] - int[>90] - int[<10]"
   # Union, then subtraction:
   "score": "int[>0,<100] - int[>90] | int[<10]"
   "score": "int[>0,<100] - (int[>90] | int[<10])"  # same thing
   # Use parenthesis to run subtraction first
   "score": "int[>0,<50] | (int[<100] - int[<10])"
   "score": "(int[<100] - int[<10]) | int[>0,<50]"
   ```

   **Note**: Union is handled before subtraction.

4. Allowing all but a specific value:

   ```python
   "specialNumber": "any - int[0]"
   ```

### Union Types (`|`)

Allows you to specify that a value can be one of multiple types.

**Syntax:**

```python
"typeA | typeB | typeC"
```

**Usage:**

- The value must match at least one of the specified types.

**Examples:**

1. Multiple possible types:

   ```python
   "data": "int | str | bool"
   ```

   Accepts an integer, string, or boolean value for the key `data`.

2. Combining with arrays:

   ```python
   "mixedList": "array[int | str]"
   ```

   Accepts a list of integers or strings.

### Conditional Ranges and Values

Specifies conditions that values must satisfy, including ranges and specific values.

**Syntax:**

- Greater than: `">value"`
- Less than: `"<value"`
- Greater than or equal to: `">=value"`
- Less than or equal to: `"<="value"`
- Range: `"start-end"`
- Specific values: `"value1,value2,value3"`

**Examples:**

1. Integer conditions:

   ```python
   "level": "int[>=1,<=10]"
   ```

   Accepts integers from 1 to 10 inclusive.

2. Double with range:

   ```python
   "latitude": "double[-90.0 - 90.0]"
   ```

   Accepts doubles between -90.0 and 90.0 inclusive.

3. Specific values:

   ```python
   "status": "int[1,2,3]"
   ```

   Accepts integers that are either 1, 2, or 3.

---

## Error Handling

```mermaid
graph TD
    Exception --> JvvException
    JvvException --> JvvRuntimeException
    JvvException --> JvvSyntaxError

    JvvRuntimeException --> UnknownProperty["UnknownProperty<br/><small>Raised when a key in config<br/>isn't defined in property types</small>"]
    JvvRuntimeException --> InvalidPropertyType["InvalidPropertyType<br/><small>Raised when a value doesn't<br/>match its type definition</small>"]
    InvalidPropertyType --> MissingRequiredKey["MissingRequiredKey<br/><small>Raised when a required key<br/>is missing from config</small>"]
    MissingRequiredKey --> MissingGroupKey["MissingGroupKey<br/><small>Raised when some keys in a<br/>property group are missing</small>"]

    JvvSyntaxError --> PropertySyntaxError["PropertySyntaxError<br/><small>Raised when property type<br/>definitions have syntax errors</small>"]

    classDef base fill:#eee,stroke:#333,stroke-width:2px;
    classDef jvv fill:#d4e6f1,stroke:#2874a6,stroke-width:2px;
    classDef runtime fill:#d5f5e3,stroke:#196f3d,stroke-width:2px;
    classDef syntax fill:#fdebd0,stroke:#b9770e,stroke-width:2px;
    classDef error fill:#fadbd8,stroke:#943126,stroke-width:2px;

    class Exception base;
    class JvvException jvv;
    class JvvRuntimeException,JvvSyntaxError runtime;
    class PropertySyntaxError syntax;
    class UnknownProperty,InvalidPropertyType,MissingRequiredKey,MissingGroupKey error;
```

---

### Types

- **str**: Basic string type.

  - Arguments:
    - `regex_pattern` (optional): A regex pattern the string must match.
  - Example: `"str[^[A-Za-z]+$]"`

- **int**: Integer type with conditions.

  - Arguments:
    - `conditions`: Inequalities (`>=`, `<=`, `>`, `<`), specific values (`value1,value2`), ranges (`start-end`).
  - Example: `"int[>=0,<=100]"`

- **double**: Double (floating-point) type with conditions.

  - Arguments:
    - Same as `int`.
  - Example: `"double[>0.0]"`

- **bool**: Boolean type.

  - Arguments: None.
  - Example: `"bool"`

- **array**: Array (list) of elements of a specified type.

  - Arguments:
    - `element_type`: Type of elements in the array.
    - `length_conditions` (optional): Conditions on the array length.
  - Example: `"array[int[>=0],>=1,<=10]"`

- **tuple**: Fixed-size sequence of elements of specified types.

  - Arguments:
    - List of element types.
  - Example: `"tuple[str, int, bool]"`

- **nil**: Represents a `None` value.

  - Arguments: None.
  - Example: `"nil"`

- **any**: Accepts any value.

  - Arguments: None.
  - Example: `"any"`

- **Type References**: Reusable type definitions.
  - Arguments:
    - `@typeName`: Reference to a named type.
  - Example:
    - Define: `"@positiveInt": "int[>0]"`
    - Use: `"userId": "@positiveInt"`

### Type Combinations

- **Union Types** (`|`): Value must match one of multiple types.

  - Syntax: `"typeA | typeB"`
  - Example: `"str | int"`

- **Subtracting Domains** (`-`): Value must match `typeA` but not `typeB`.
  - Syntax: `"typeA - typeB"`
  - Example: `"int - int[13]"` (any integer except 13)

### Escaping Characters

- `!`: Escapes commas, slashes, and other jsonvv characters within strings.
- `\`: Escapes within a regex pattern.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/daijro/camoufox/tree/main/pythonlib/jsonvv",
    "name": "jsonvv",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.8",
    "maintainer_email": null,
    "keywords": "json, validator, validation, typing",
    "author": "daijro",
    "author_email": "daijro.dev@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/0a/01/d7a719321baf7a93d444054840d9ca17c4bd5ccde58cb7af7b7e620762c2/jsonvv-0.2.2.tar.gz",
    "platform": null,
    "description": "# JSONvv\n\nJSON value validator\n\n## Overview\n\nThis is a simple JSON schema validator library. It was created for Camoufox to validate passed user configurations. Because I found it useful for other projects, I decided to extract it into a separate library.\n\nJSONvv's syntax parser is written in pure Python. It does not rely on any dependencies.\n\n### Example\n\n<table>\n<tr>\n<th width=\"50%\">Configuration</th>\n<th width=\"50%\">Validator</th>\n</tr>\n<tr>\n<td width=\"50%\">\n\n```python\nconfig = {\n    \"username\": \"johndoe\",\n    \"email\": \"johndoe@example.com\",\n    \"age\": 30,\n    \"chat\": \"Hello world!\",\n    \"preferences\": {\n        \"notifications\": True,\n        \"theme\": \"dark\"\n    },\n    \"allowed_commands\": [\n        \"/help\", \"/time\", \"/weather\"\n    ],\n    \"location\": [40.7128, -74.0060],\n    \"hobbies\": [\n        {\n            \"name\": \"Traveling\",\n            \"cities\": [\"Paris\", \"London\"]\n        },\n        {\n            \"name\": \"reading\",\n            \"hours\": {\n                \"Sunday\": 2,\n                \"Monday\": 3,\n            }\n        }\n    ]\n}\n```\n\n</td>\n<td width=\"50%\">\n\n```python\nvalidator = {\n    \"username\": \"str\",  # Basic username\n    \"email\": \"str[/\\S+@\\S+\\.\\S+/]\",  # Validate emails\n    \"age\": \"int[>=18]\",  # Age must be 18 or older\n    \"chat\": \"str | nil\",  # Optional chat message\n    \"preferences\": {\n        \"notifications\": \"bool\",\n        \"theme\": \"str[light, dark] | nil\",  # Optional theme\n    },\n    # Commands must start with \"/\", but not contain \"sudo\"\n    \"allowed_commands\": \"array[str[/^//] - str[/sudo/]]\",\n    # Validate coordinate ranges\n    \"location\": \"tuple[double[-90 - 90], double[-180 - 180]]\",\n    # Handle an array of hobby types\n    \"hobbies\": \"array[@traveling | @other, >=1]\",\n    \"@traveling\": {\n        # Require 1 or more cities/countries iff name is \"Traveling\"\n        \"*name,type\": \"str[Traveling]\",\n        \"*cities,countries\": \"array[str[A-Za-z*], >=1]\",\n    },\n    \"@other\": {\n        \"name,type\": \"str - str[Traveling]\",  # Non-traveling types\n        # If hour(s) is specified, require days have >0 hours\n        \"/hours?/\": {\n            \"*/day$/\": \"int[>0]\"\n        }\n    }\n}\n```\n\n</td>\n</tr>\n</table>\n\n<hr width=50>\n\nThen, validate the configuration like this:\n\n```python\nfrom jsonvv import JsonValidator, JvvRuntimeException\n\nval = JsonValidator(validator)\ntry:\n   val.validate(config)\nexcept JvvRuntimeException as exc:\n   print(\"Failed:\", exc)\nelse:\n   print('Config is valid!')\n```\n\n---\n\n## Table of Contents\n\n- [Key Syntax](#key-syntax)\n  - [Regex patterns](#regex-patterns)\n  - [Lists of possible values](#lists-of-possible-values)\n  - [Required fields (`*`)](#required-fields-)\n  - [Grouping keys (`$`)](#grouping-keys-)\n- [Supported Types](#supported-types)\n  - [String (`str`)](#string-str)\n  - [Integer (`int`)](#integer-int)\n  - [Double (`double`)](#double-double)\n  - [Boolean (`bool`)](#boolean-bool)\n  - [Array (`array`)](#array-array)\n  - [Tuple (`tuple`)](#tuple-tuple)\n  - [Nested Dictionaries](#nested-dictionaries)\n  - [Nil (`nil`)](#nil-nil)\n  - [Any (`any`)](#any-any)\n  - [Required fields (`*`)](#required-fields-)\n  - [Type References (`@`)](#type-references-)\n- [Advanced Features](#advanced-features)\n  - [Subtracting Domains (`-`)](#subtracting-domains--)\n  - [Union Types (`|`)](#union-types-)\n  - [Conditional Ranges and Values](#conditional-ranges-and-values)\n- [Error Handling](#error-handling)\n\n---\n\n## Keys Syntax\n\nDictionary keys can be specified in several possible ways:\n\n- `\"key\": \"type\"`\n- `\"key1,key2,key3\": \"type\"`\n- `\"/key\\d+/\": \"type\"`\n- `\"*required_key\": \"type\"`\n\n### Regex patterns\n\nTo use regex in a key, wrap it in `/ ... /`.\n\n**Syntax:**\n\n```python\n\"/key\\d+/\": \"type\"\n```\n\n### Lists of possible values\n\nTo specify a list of keys, use a comma-separated string.\n\n**Syntax:**\n\n```python\n\"key1,key2,key3\": \"type\"\n\"/k[ey]{2}1/,key2\": \"type\"\n```\n\nTo escape a comma, use `!`.\n\n### Required fields (`*`)\n\nFields marked with `*` are required. The validation will fail without them.\n\n**Syntax:**\n\n```python\n\"*key1\": \"type\"\n\"*/key\\d+/\": \"type\"\n```\n\n### Grouping keys (`$`)\n\nFields that end with `$group_name` are grouped together. If one of the keys is set, all of the keys in the group must also be set as well.\n\n**Syntax:**\n\n```python\n\"isEnabled$group1\": \"bool\"\n\"value$group1\": \"int[>0]\"\n```\n\nThis will require both `value` is set if and only if `isEnabled` is set.\n\nMultiple `$` can be used to create more complex group dependencies.\n\n---\n\n## Supported Types\n\n### String (`str`)\n\nRepresents a string value. Optionally, you can specify a regex pattern that the string must match.\n\n**Syntax:**\n\n- Basic string: `\"str\"`\n- With regex pattern: `\"str[regex_pattern]\"`\n- The escape character for regex is `\\`, and for commas is `_`.\n\n**Arguments:**\n\n- `regex_pattern`: A regular expression that the string must match. If not specified, any string is accepted.\n\n**Examples:**\n\n1. Basic string:\n\n   ```python\n   \"username\": \"str\"\n   ```\n\n   Accepts any string value for the key `username`.\n\n2. String with regex pattern:\n\n   ```python\n   \"fullname\": \"str[/[A-Z][a-z]+ [A-Z][a-z]+/]\"\n   ```\n\n   Accepts a string that matches the pattern of a first and last name starting with uppercase letters.\n\n### Integer (`int`)\n\nRepresents an integer value. You can specify conditions like exact values, ranges, and inequalities.\n\n**Syntax:**\n\n- Basic integer: `\"int\"`\n- With conditions: `\"int[conditions]\"`\n\n**Arguments:**\n\n- `conditions`: A comma-separated list of conditions.\n\n**Condition Operators:**\n\n- `==`: Equal to a specific value.\n- `>=`: Greater than or equal to a value.\n- `<=`: Less than or equal to a value.\n- `>`: Greater than a value.\n- `<`: Less than a value.\n- `range`: A range between two values (inclusive).\n\n**Examples:**\n\n1. Basic integer:\n\n   ```python\n   \"age\": \"int\"\n   ```\n\n   Accepts any integer value for the key `age`.\n\n2. Integer with conditions:\n\n   ```python\n   \"userage\": \"int[>=0, <=120]\"\n   ```\n\n   Accepts integer values between 0 and 120 inclusive.\n\n3. Specific values and ranges\n\n   ```python\n   \"rating\": \"int[1-5]\"\n   \"rating\": \"int[1,2,3,4-5]\"\n   ```\n\n   Accepts integer values 1, 2, 3, 4, or 5.\n\n4. Ranges with negative numbers:\n\n   ```python\n   \"rating\": \"int[-100 - -90]\"\n   ```\n\n   Accepts integer values from -100 to -90.\n\n### Double (`double`)\n\nRepresents a floating-point number. Supports the same conditions as integers.\n\n**Syntax:**\n\n- Basic double: `\"double\"`\n- With conditions: `\"double[conditions]\"`\n\n**Arguments:**\n\n- `conditions`: A comma-separated list of conditions.\n\n**Examples:**\n\n1. Basic double:\n\n   ```python\n   \"price\": \"double\"\n   ```\n\n   Accepts any floating-point number for the key `price`.\n\n2. Double with conditions:\n\n   ```python\n   \"percentage\": \"double[>=0.0,<=100.0]\"\n   ```\n\n   Accepts double values between 0.0 and 100.0 inclusive.\n\n### Boolean (`bool`)\n\nRepresents a boolean value (`True` or `False`).\n\n**Syntax:**\n\n```python\n\"isActive\": \"bool\"\n```\n\nAccepts a boolean value for the key `isActive`.\n\n### Array (`array`)\n\nRepresents a list of elements of a specified type. You can specify conditions on the length of the array.\n\n**Syntax:**\n\n- Basic array: `\"array[element_type]\"`\n- With length conditions: `\"array[element_type,length_conditions]\"`\n\n**Arguments:**\n\n- `element_type`: The type of the elements in the array.\n- `length_conditions`: Conditions on the array length (same as integer conditions).\n\n**Examples:**\n\n1. Basic array:\n\n   ```python\n   \"tags\": \"array[str]\"\n   ```\n\n   Accepts a list of strings for the key `tags`.\n\n2. Array with length conditions:\n\n   ```python\n   \"scores\": \"array[int[>=0,<=100],>=1,<=5]\"\n   ```\n\n   Accepts a list of 1 to 5 integers between 0 and 100 inclusive.\n\n3. Fixed-length array:\n\n   ```python\n   \"coordinates\": \"array[double, 2]\"\n   ```\n\n   Accepts a list of exactly 2 double values.\n\n4. More complex restraints:\n   ```python\n   \"coordinates\": \"array[array[int[>0]] - tuple[1, 1]], 2]\"\n   ```\n\n### Tuple (`tuple`)\n\nRepresents a fixed-size sequence of elements of specified types.\n\n**Syntax:**\n\n```python\n\"tuple[element_type1, element_type2]\"\n```\n\n**Arguments:**\n\n- `element_typeN`: The type of the Nth element in the tuple.\n\n**Examples:**\n\n1. Basic tuple:\n\n   ```python\n   \"point\": \"tuple[int, int]\"\n   ```\n\n   Accepts a tuple or list of two integers.\n\n2. Tuple with mixed types:\n\n   ```python\n   \"userInfo\": \"tuple[str, int, bool]\"\n   ```\n\n   Accepts a tuple of a string, an integer, and a boolean.\n\n### Nested Dictionaries\n\nRepresents a nested dictionary structure. Dictionaries are defined using Python's dictionary syntax `{}` in the type definitions.\n\n**Syntax:**\n\n```python\n\"settings\": {\n    \"volume\": \"int[>=0,<=100]\",\n    \"brightness\": \"int[>=0,<=100]\",\n    \"mode\": \"str\"\n}\n```\n\n**Usage:**\n\n- Define the expected keys and their types within the dictionary.\n- You can use all the supported types for the values.\n\n**Examples:**\n\n1. Nested dictionary:\n\n   ```python\n   \"user\": {\n       \"name\": \"str\",\n       \"age\": \"int[>=0]\",\n       \"preferences\": {\n           \"theme\": \"str\",\n           \"notifications\": \"bool\"\n       }\n   }\n   ```\n\n   Defines a nested dictionary structure for the key `user`.\n\n### Nil (`nil`)\n\nRepresents a `None` value.\n\n**Syntax:**\n\n```python\n\"optionalValue\": \"int | nil\"\n```\n\n**Usage:**\n\n- Use `nil` to allow a value to be `None`.\n- Often used with union types to specify optional values.\n\n### Any (`any`)\n\nRepresents any value.\n\n**Syntax:**\n\n```python\n\"metadata\": \"any\"\n```\n\n**Usage:**\n\n- Use `any` when any value is acceptable.\n- Useful for keys where the value is not constrained.\n\n### Type References (`@`)\n\nAllows you to define reusable types and reference them.\n\n**Syntax:**\n\n- Define a named type:\n\n  ```python\n  \"@typeName\": \"type_definition\"\n  ```\n\n- Reference a named type:\n\n  ```python\n  \"key\": \"@typeName\"\n  ```\n\n**Examples:**\n\n1. Defining and using a named type:\n\n   ```python\n   \"@positiveInt\": \"int[>0]\"\n   \"userId\": \"@positiveInt\"\n   ```\n\n   Defines a reusable type `@positiveInt` and uses it for the key `userId`.\n\n---\n\n## Advanced Features\n\n### Subtracting Domains (`-`)\n\nAllows you to specify that a value should not match a certain type or condition.\n\n**Syntax:**\n\n```python\n\"typeA - typeB\"\n```\n\n**Usage:**\n\n- The value must match `typeA` but not `typeB`.\n\n**Examples:**\n\n1. Excluding certain strings:\n\n   ```python\n   \"message\": \"str - str[.*error.*]\"\n   ```\n\n   Accepts any string that does not match the regex pattern `.*error.*`.\n\n2. Excluding a range of numbers:\n\n   ```python\n   \"score\": \"int[0-100] - int[>=90]\"\n   ```\n\n   Accepts integers between 0 and 100, excluding values greater than or equal to 90.\n\n3. Excluding multiple types:\n\n   ```python\n   \"score\": \"int[>0,<100] - int[>90] - int[<10]\"\n   # Union, then subtraction:\n   \"score\": \"int[>0,<100] - int[>90] | int[<10]\"\n   \"score\": \"int[>0,<100] - (int[>90] | int[<10])\"  # same thing\n   # Use parenthesis to run subtraction first\n   \"score\": \"int[>0,<50] | (int[<100] - int[<10])\"\n   \"score\": \"(int[<100] - int[<10]) | int[>0,<50]\"\n   ```\n\n   **Note**: Union is handled before subtraction.\n\n4. Allowing all but a specific value:\n\n   ```python\n   \"specialNumber\": \"any - int[0]\"\n   ```\n\n### Union Types (`|`)\n\nAllows you to specify that a value can be one of multiple types.\n\n**Syntax:**\n\n```python\n\"typeA | typeB | typeC\"\n```\n\n**Usage:**\n\n- The value must match at least one of the specified types.\n\n**Examples:**\n\n1. Multiple possible types:\n\n   ```python\n   \"data\": \"int | str | bool\"\n   ```\n\n   Accepts an integer, string, or boolean value for the key `data`.\n\n2. Combining with arrays:\n\n   ```python\n   \"mixedList\": \"array[int | str]\"\n   ```\n\n   Accepts a list of integers or strings.\n\n### Conditional Ranges and Values\n\nSpecifies conditions that values must satisfy, including ranges and specific values.\n\n**Syntax:**\n\n- Greater than: `\">value\"`\n- Less than: `\"<value\"`\n- Greater than or equal to: `\">=value\"`\n- Less than or equal to: `\"<=\"value\"`\n- Range: `\"start-end\"`\n- Specific values: `\"value1,value2,value3\"`\n\n**Examples:**\n\n1. Integer conditions:\n\n   ```python\n   \"level\": \"int[>=1,<=10]\"\n   ```\n\n   Accepts integers from 1 to 10 inclusive.\n\n2. Double with range:\n\n   ```python\n   \"latitude\": \"double[-90.0 - 90.0]\"\n   ```\n\n   Accepts doubles between -90.0 and 90.0 inclusive.\n\n3. Specific values:\n\n   ```python\n   \"status\": \"int[1,2,3]\"\n   ```\n\n   Accepts integers that are either 1, 2, or 3.\n\n---\n\n## Error Handling\n\n```mermaid\ngraph TD\n    Exception --> JvvException\n    JvvException --> JvvRuntimeException\n    JvvException --> JvvSyntaxError\n\n    JvvRuntimeException --> UnknownProperty[\"UnknownProperty<br/><small>Raised when a key in config<br/>isn't defined in property types</small>\"]\n    JvvRuntimeException --> InvalidPropertyType[\"InvalidPropertyType<br/><small>Raised when a value doesn't<br/>match its type definition</small>\"]\n    InvalidPropertyType --> MissingRequiredKey[\"MissingRequiredKey<br/><small>Raised when a required key<br/>is missing from config</small>\"]\n    MissingRequiredKey --> MissingGroupKey[\"MissingGroupKey<br/><small>Raised when some keys in a<br/>property group are missing</small>\"]\n\n    JvvSyntaxError --> PropertySyntaxError[\"PropertySyntaxError<br/><small>Raised when property type<br/>definitions have syntax errors</small>\"]\n\n    classDef base fill:#eee,stroke:#333,stroke-width:2px;\n    classDef jvv fill:#d4e6f1,stroke:#2874a6,stroke-width:2px;\n    classDef runtime fill:#d5f5e3,stroke:#196f3d,stroke-width:2px;\n    classDef syntax fill:#fdebd0,stroke:#b9770e,stroke-width:2px;\n    classDef error fill:#fadbd8,stroke:#943126,stroke-width:2px;\n\n    class Exception base;\n    class JvvException jvv;\n    class JvvRuntimeException,JvvSyntaxError runtime;\n    class PropertySyntaxError syntax;\n    class UnknownProperty,InvalidPropertyType,MissingRequiredKey,MissingGroupKey error;\n```\n\n---\n\n### Types\n\n- **str**: Basic string type.\n\n  - Arguments:\n    - `regex_pattern` (optional): A regex pattern the string must match.\n  - Example: `\"str[^[A-Za-z]+$]\"`\n\n- **int**: Integer type with conditions.\n\n  - Arguments:\n    - `conditions`: Inequalities (`>=`, `<=`, `>`, `<`), specific values (`value1,value2`), ranges (`start-end`).\n  - Example: `\"int[>=0,<=100]\"`\n\n- **double**: Double (floating-point) type with conditions.\n\n  - Arguments:\n    - Same as `int`.\n  - Example: `\"double[>0.0]\"`\n\n- **bool**: Boolean type.\n\n  - Arguments: None.\n  - Example: `\"bool\"`\n\n- **array**: Array (list) of elements of a specified type.\n\n  - Arguments:\n    - `element_type`: Type of elements in the array.\n    - `length_conditions` (optional): Conditions on the array length.\n  - Example: `\"array[int[>=0],>=1,<=10]\"`\n\n- **tuple**: Fixed-size sequence of elements of specified types.\n\n  - Arguments:\n    - List of element types.\n  - Example: `\"tuple[str, int, bool]\"`\n\n- **nil**: Represents a `None` value.\n\n  - Arguments: None.\n  - Example: `\"nil\"`\n\n- **any**: Accepts any value.\n\n  - Arguments: None.\n  - Example: `\"any\"`\n\n- **Type References**: Reusable type definitions.\n  - Arguments:\n    - `@typeName`: Reference to a named type.\n  - Example:\n    - Define: `\"@positiveInt\": \"int[>0]\"`\n    - Use: `\"userId\": \"@positiveInt\"`\n\n### Type Combinations\n\n- **Union Types** (`|`): Value must match one of multiple types.\n\n  - Syntax: `\"typeA | typeB\"`\n  - Example: `\"str | int\"`\n\n- **Subtracting Domains** (`-`): Value must match `typeA` but not `typeB`.\n  - Syntax: `\"typeA - typeB\"`\n  - Example: `\"int - int[13]\"` (any integer except 13)\n\n### Escaping Characters\n\n- `!`: Escapes commas, slashes, and other jsonvv characters within strings.\n- `\\`: Escapes within a regex pattern.\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "JSON value validator",
    "version": "0.2.2",
    "project_urls": {
        "Homepage": "https://github.com/daijro/camoufox/tree/main/pythonlib/jsonvv",
        "Repository": "https://github.com/daijro/camoufox"
    },
    "split_keywords": [
        "json",
        " validator",
        " validation",
        " typing"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b314e69b23dc5e7b69aa5b2a4e0f5d60ca280865bebb9e7fd4db4974574e5589",
                "md5": "3722b5b8cefd5979302d48daf352ce4b",
                "sha256": "bb574c7c3cea87106516e98f67dbcd7fde59a0e5d3ad0cef2ddb6cc3f9c9102f"
            },
            "downloads": -1,
            "filename": "jsonvv-0.2.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3722b5b8cefd5979302d48daf352ce4b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.8",
            "size": 15186,
            "upload_time": "2024-11-28T04:57:49",
            "upload_time_iso_8601": "2024-11-28T04:57:49.745807Z",
            "url": "https://files.pythonhosted.org/packages/b3/14/e69b23dc5e7b69aa5b2a4e0f5d60ca280865bebb9e7fd4db4974574e5589/jsonvv-0.2.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0a01d7a719321baf7a93d444054840d9ca17c4bd5ccde58cb7af7b7e620762c2",
                "md5": "842cff54c783a034dfb81ea521d15fd8",
                "sha256": "0eec3a6515ce05387d73d412a7505318136267a511cbdd4dbeb63959a1a751c6"
            },
            "downloads": -1,
            "filename": "jsonvv-0.2.2.tar.gz",
            "has_sig": false,
            "md5_digest": "842cff54c783a034dfb81ea521d15fd8",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8",
            "size": 17313,
            "upload_time": "2024-11-28T04:57:51",
            "upload_time_iso_8601": "2024-11-28T04:57:51.296906Z",
            "url": "https://files.pythonhosted.org/packages/0a/01/d7a719321baf7a93d444054840d9ca17c4bd5ccde58cb7af7b7e620762c2/jsonvv-0.2.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-28 04:57:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "daijro",
    "github_project": "camoufox",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "jsonvv"
}
        
Elapsed time: 0.50676s