| .. | ||
| jsonvv | ||
| publish.sh | ||
| pyproject.toml | ||
| README.md | ||
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
| Configuration | Validator |
|---|---|
|
|
Then, validate the configuration like this:
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
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:
"/key\d+/": "type"
Lists of possible values
To specify a list of keys, use a comma-separated string.
Syntax:
"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:
"*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:
"isEnabled$group1": "bool"
"value$group1": "int[>0]"
This will require both value is set if and only if isEnabled is set.
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:
-
Basic string:
"username": "str"Accepts any string value for the key
username. -
String with regex pattern:
"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:
-
Basic integer:
"age": "int"Accepts any integer value for the key
age. -
Integer with conditions:
"userage": "int[>=0, <=120]"Accepts integer values between 0 and 120 inclusive.
-
Specific values and ranges
"rating": "int[1-5]" "rating": "int[1,2,3,4-5]"Accepts integer values 1, 2, 3, 4, or 5.
-
Ranges with negative numbers:
"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:
-
Basic double:
"price": "double"Accepts any floating-point number for the key
price. -
Double with conditions:
"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:
"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:
-
Basic array:
"tags": "array[str]"Accepts a list of strings for the key
tags. -
Array with length conditions:
"scores": "array[int[>=0,<=100],>=1,<=5]"Accepts a list of 1 to 5 integers between 0 and 100 inclusive.
-
Fixed-length array:
"coordinates": "array[double, 2]"Accepts a list of exactly 2 double values.
-
More complex restraints:
"coordinates": "array[array[int[>0]] - tuple[1, 1]], 2]"
Tuple (tuple)
Represents a fixed-size sequence of elements of specified types.
Syntax:
"tuple[element_type1, element_type2]"
Arguments:
element_typeN: The type of the Nth element in the tuple.
Examples:
-
Basic tuple:
"point": "tuple[int, int]"Accepts a tuple or list of two integers.
-
Tuple with mixed types:
"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:
"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:
-
Nested dictionary:
"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:
"optionalValue": "int | nil"
Usage:
- Use
nilto allow a value to beNone. - Often used with union types to specify optional values.
Any (any)
Represents any value.
Syntax:
"metadata": "any"
Usage:
- Use
anywhen 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:
"@typeName": "type_definition" -
Reference a named type:
"key": "@typeName"
Examples:
-
Defining and using a named type:
"@positiveInt": "int[>0]" "userId": "@positiveInt"Defines a reusable type
@positiveIntand uses it for the keyuserId.
Advanced Features
Subtracting Domains (-)
Allows you to specify that a value should not match a certain type or condition.
Syntax:
"typeA - typeB"
Usage:
- The value must match
typeAbut nottypeB.
Examples:
-
Excluding certain strings:
"message": "str - str[.*error.*]"Accepts any string that does not match the regex pattern
.*error.*. -
Excluding a range of numbers:
"score": "int[0-100] - int[>=90]"Accepts integers between 0 and 100, excluding values greater than or equal to 90.
-
Excluding multiple types:
"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.
-
Allowing all but a specific value:
"specialNumber": "any - int[0]"
Union Types (|)
Allows you to specify that a value can be one of multiple types.
Syntax:
"typeA | typeB | typeC"
Usage:
- The value must match at least one of the specified types.
Examples:
-
Multiple possible types:
"data": "int | str | bool"Accepts an integer, string, or boolean value for the key
data. -
Combining with arrays:
"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:
-
Integer conditions:
"level": "int[>=1,<=10]"Accepts integers from 1 to 10 inclusive.
-
Double with range:
"latitude": "double[-90.0 - 90.0]"Accepts doubles between -90.0 and 90.0 inclusive.
-
Specific values:
"status": "int[1,2,3]"Accepts integers that are either 1, 2, or 3.
Error Handling
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]+$]"
- Arguments:
-
int: Integer type with conditions.
- Arguments:
conditions: Inequalities (>=,<=,>,<), specific values (value1,value2), ranges (start-end).
- Example:
"int[>=0,<=100]"
- Arguments:
-
double: Double (floating-point) type with conditions.
- Arguments:
- Same as
int.
- Same as
- Example:
"double[>0.0]"
- Arguments:
-
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]"
- Arguments:
-
tuple: Fixed-size sequence of elements of specified types.
- Arguments:
- List of element types.
- Example:
"tuple[str, int, bool]"
- Arguments:
-
nil: Represents a
Nonevalue.- 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"
- Define:
- Arguments:
Type Combinations
-
Union Types (
|): Value must match one of multiple types.- Syntax:
"typeA | typeB" - Example:
"str | int"
- Syntax:
-
Subtracting Domains (
-): Value must matchtypeAbut nottypeB.- Syntax:
"typeA - typeB" - Example:
"int - int[13]"(any integer except 13)
- Syntax:
Escaping Characters
!: Escapes commas, slashes, and other jsonvv characters within strings.\: Escapes within a regex pattern.