0
# Utilities and Type Checking
1
2
Utility classes, helper functions, and type validation system for JSON Schema processing. This module provides type checking capabilities, internal utilities, CLI interface, and reflection helpers.
3
4
## Capabilities
5
6
### Type Checking System
7
8
Flexible type validation system for JSON Schema type keyword validation with customizable type checkers.
9
10
```python { .api }
11
class TypeChecker:
12
"""Registry for type checking functions."""
13
14
def __init__(self, type_checkers: dict[str, Callable] | None = None) -> None:
15
"""
16
Initialize type checker.
17
18
Args:
19
type_checkers: Dictionary mapping type names to check functions
20
"""
21
22
def is_type(self, instance: Any, type: str) -> bool:
23
"""
24
Check if instance is of the specified type.
25
26
Args:
27
instance: Value to check
28
type: Type name to check against
29
30
Returns:
31
True if instance matches type, False otherwise
32
"""
33
34
def redefine(self, type: str, fn: Callable[[Any, Any], bool]) -> TypeChecker:
35
"""
36
Create new TypeChecker with redefined type check.
37
38
Args:
39
type: Type name to redefine
40
fn: New type checking function
41
42
Returns:
43
New TypeChecker instance
44
"""
45
46
def redefine_many(self, definitions: dict[str, Callable] | None = None) -> TypeChecker:
47
"""
48
Create new TypeChecker with multiple redefined type checks.
49
50
Args:
51
definitions: Dictionary of type definitions
52
53
Returns:
54
New TypeChecker instance
55
"""
56
57
def remove(self, *types: str) -> TypeChecker:
58
"""
59
Create new TypeChecker with specified types removed.
60
61
Args:
62
*types: Type names to remove
63
64
Returns:
65
New TypeChecker instance
66
"""
67
68
def __lt__(self, other: TypeChecker) -> bool:
69
"""Less than comparison for TypeChecker instances."""
70
71
def __le__(self, other: TypeChecker) -> bool:
72
"""Less than or equal comparison for TypeChecker instances."""
73
74
def __gt__(self, other: TypeChecker) -> bool:
75
"""Greater than comparison for TypeChecker instances."""
76
77
def __ge__(self, other: TypeChecker) -> bool:
78
"""Greater than or equal comparison for TypeChecker instances."""
79
```
80
81
Usage example:
82
83
```python
84
from jsonschema import TypeChecker, Draft7Validator
85
86
# Create custom type checker
87
def is_positive_number(checker, instance):
88
return isinstance(instance, (int, float)) and instance > 0
89
90
custom_types = TypeChecker()
91
custom_types = custom_types.redefine('positive-number', is_positive_number)
92
93
# Use with validator (requires custom validator creation)
94
# This is typically done through the create() function
95
```
96
97
### Pre-configured Type Checkers
98
99
Ready-to-use type checkers for different JSON Schema draft versions.
100
101
```python { .api }
102
# Draft-specific type checkers with appropriate type definitions
103
draft3_type_checker: TypeChecker
104
draft4_type_checker: TypeChecker
105
draft6_type_checker: TypeChecker
106
draft7_type_checker: TypeChecker
107
```
108
109
### Built-in Type Checking Functions
110
111
Standard type checking functions used by JSON Schema validators.
112
113
```python { .api }
114
def is_array(checker: TypeChecker, instance: Any) -> bool:
115
"""Check if instance is an array (list)."""
116
117
def is_bool(checker: TypeChecker, instance: Any) -> bool:
118
"""Check if instance is a boolean."""
119
120
def is_integer(checker: TypeChecker, instance: Any) -> bool:
121
"""Check if instance is an integer."""
122
123
def is_null(checker: TypeChecker, instance: Any) -> bool:
124
"""Check if instance is null (None)."""
125
126
def is_number(checker: TypeChecker, instance: Any) -> bool:
127
"""Check if instance is a number (int or float)."""
128
129
def is_object(checker: TypeChecker, instance: Any) -> bool:
130
"""Check if instance is an object (dict)."""
131
132
def is_string(checker: TypeChecker, instance: Any) -> bool:
133
"""Check if instance is a string."""
134
135
def is_any(checker: TypeChecker, instance: Any) -> bool:
136
"""Always returns True (matches any type)."""
137
```
138
139
### URI Dictionary
140
141
URI-aware dictionary for storing schemas with proper URI normalization.
142
143
```python { .api }
144
class URIDict(MutableMapping[Any, Any]):
145
"""Dictionary that normalizes URI keys."""
146
147
store: dict
148
149
def __init__(self, *args, **kwargs) -> None:
150
"""Initialize URI dictionary."""
151
152
def normalize(self, uri: str) -> str:
153
"""
154
Normalize URI for consistent storage.
155
156
Args:
157
uri: URI to normalize
158
159
Returns:
160
Normalized URI string
161
"""
162
163
def __getitem__(self, uri: str) -> Any:
164
"""Get item by URI key."""
165
166
def __setitem__(self, uri: str, value: Any) -> None:
167
"""Set item by URI key."""
168
169
def __delitem__(self, uri: str) -> None:
170
"""Delete item by URI key."""
171
172
def __iter__(self) -> Iterator[str]:
173
"""Iterate over URI keys."""
174
175
def __len__(self) -> int:
176
"""Get number of stored items."""
177
```
178
179
Usage example:
180
181
```python
182
from jsonschema._utils import URIDict
183
184
# URI dictionary automatically normalizes keys
185
uri_store = URIDict()
186
uri_store['http://example.com/schema'] = {"type": "string"}
187
uri_store['http://example.com/schema/'] = {"type": "number"} # Different URI
188
189
print(len(uri_store)) # May be 1 or 2 depending on normalization
190
```
191
192
### Sentinel Values and Utilities
193
194
Utility classes and functions for internal JSON Schema processing.
195
196
```python { .api }
197
class Unset:
198
"""Sentinel class for unset values."""
199
200
def load_schema(name: str) -> dict:
201
"""
202
Load a built-in schema by name.
203
204
Args:
205
name: Schema name to load
206
207
Returns:
208
Schema dictionary
209
"""
210
211
def indent(string: str, times: int = 1) -> str:
212
"""
213
Indent string by specified number of levels.
214
215
Args:
216
string: String to indent
217
times: Number of indentation levels
218
219
Returns:
220
Indented string
221
"""
222
223
def format_as_index(indices: Sequence[str | int]) -> str:
224
"""
225
Format indices as readable path string.
226
227
Args:
228
indices: Sequence of path indices
229
230
Returns:
231
Formatted path string
232
"""
233
234
def find_additional_properties(instance: dict, schema: dict) -> None:
235
"""
236
Find additional properties not defined in schema.
237
238
Args:
239
instance: Instance to check
240
schema: Schema with property definitions
241
242
Returns:
243
None (modifies state internally)
244
"""
245
246
def extras_msg(extras: Iterable[str]) -> str:
247
"""
248
Create message for extra properties.
249
250
Args:
251
extras: Extra property names
252
253
Returns:
254
Formatted message string
255
"""
256
257
def types_msg(instance: Any, types: Iterable[str]) -> str:
258
"""
259
Create message for type mismatch.
260
261
Args:
262
instance: Instance that failed type check
263
types: Expected types
264
265
Returns:
266
Formatted message string
267
"""
268
269
def flatten(suitable_for_isinstance: Iterable[type]) -> tuple[type, ...]:
270
"""
271
Flatten types suitable for isinstance check.
272
273
Args:
274
suitable_for_isinstance: Types to flatten
275
276
Returns:
277
Flattened type tuple
278
"""
279
280
def ensure_list(thing: Any) -> list:
281
"""
282
Ensure value is a list.
283
284
Args:
285
thing: Value to convert
286
287
Returns:
288
List containing the value or the value itself if already a list
289
"""
290
291
def equal(one: Any, two: Any) -> bool:
292
"""
293
Test equality with JSON Schema semantics.
294
295
Args:
296
one: First value
297
two: Second value
298
299
Returns:
300
True if values are equal according to JSON Schema rules
301
"""
302
303
def unbool(element: Any, true: Any = True, false: Any = False) -> Any:
304
"""
305
Convert boolean to other values.
306
307
Args:
308
element: Value to convert
309
true: Value to return for True
310
false: Value to return for False
311
312
Returns:
313
Converted value
314
"""
315
316
def uniq(container: Iterable[Any]) -> list[Any]:
317
"""
318
Remove duplicates from iterable while preserving order.
319
320
Args:
321
container: Iterable to deduplicate
322
323
Returns:
324
List with duplicates removed
325
"""
326
```
327
328
### Command Line Interface
329
330
CLI functions for command-line JSON Schema validation.
331
332
```python { .api }
333
def parse_args(args: list[str]) -> argparse.Namespace:
334
"""
335
Parse command line arguments.
336
337
Args:
338
args: Command line arguments
339
340
Returns:
341
Parsed arguments namespace
342
"""
343
344
def main(args: list[str] | None = None) -> None:
345
"""
346
Main CLI entry point.
347
348
Args:
349
args: Command line arguments (sys.argv if None)
350
"""
351
352
def run(
353
arguments: argparse.Namespace,
354
stdout: IO[str] = sys.stdout,
355
stderr: IO[str] = sys.stderr
356
) -> int:
357
"""
358
Run validation with parsed arguments.
359
360
Args:
361
arguments: Parsed command line arguments
362
stdout: Output stream
363
stderr: Error stream
364
365
Returns:
366
Exit code (0 for success)
367
"""
368
369
# CLI argument parser
370
parser: argparse.ArgumentParser
371
```
372
373
Usage example:
374
375
```python
376
import sys
377
from jsonschema.cli import main
378
379
# Run CLI validation
380
sys.argv = ['jsonschema', '-i', 'data.json', 'schema.json']
381
main() # Validates data.json against schema.json
382
```
383
384
### Reflection Utilities
385
386
Helper functions for dynamic importing and name resolution.
387
388
```python { .api }
389
class InvalidName(ValueError):
390
"""Exception for invalid names."""
391
392
class ModuleNotFound(InvalidName):
393
"""Exception when module cannot be found."""
394
395
class ObjectNotFound(InvalidName):
396
"""Exception when object cannot be found in module."""
397
398
def namedAny(name: str) -> Any:
399
"""
400
Import and return object by fully qualified name.
401
402
Args:
403
name: Fully qualified name (e.g., 'module.submodule.object')
404
405
Returns:
406
Imported object
407
408
Raises:
409
ModuleNotFound: If module cannot be imported
410
ObjectNotFound: If object cannot be found in module
411
InvalidName: If name format is invalid
412
"""
413
414
def reraise(exception: Exception, traceback: Any) -> None:
415
"""
416
Re-raise exception with traceback.
417
418
Args:
419
exception: Exception to re-raise
420
traceback: Exception traceback
421
"""
422
```
423
424
Usage example:
425
426
```python
427
from jsonschema._reflect import namedAny
428
429
# Dynamically import function
430
validate_func = namedAny('jsonschema.validate')
431
# Now validate_func is the same as: from jsonschema import validate
432
433
# Import class
434
validator_class = namedAny('jsonschema.Draft7Validator')
435
```
436
437
## Usage Examples
438
439
### Custom Type Checker
440
441
```python
442
from jsonschema import TypeChecker, create, ValidationError
443
444
# Define custom type checking functions
445
def is_positive_int(checker, instance):
446
return isinstance(instance, int) and instance > 0
447
448
def is_email_like(checker, instance):
449
return isinstance(instance, str) and '@' in instance
450
451
# Create custom type checker
452
custom_types = TypeChecker({
453
'positive-int': is_positive_int,
454
'email-like': is_email_like
455
})
456
457
# Create custom validator with new types
458
meta_schema = {
459
"$schema": "http://json-schema.org/draft-07/schema#",
460
"type": "object"
461
}
462
463
CustomValidator = create(
464
meta_schema=meta_schema,
465
type_checker=custom_types
466
)
467
468
# Use custom validator
469
schema = {
470
"type": "object",
471
"properties": {
472
"user_id": {"type": "positive-int"},
473
"contact": {"type": "email-like"}
474
}
475
}
476
477
validator = CustomValidator(schema)
478
479
# Valid data
480
validator.validate({"user_id": 123, "contact": "user@domain.com"})
481
482
# Invalid data
483
try:
484
validator.validate({"user_id": -1, "contact": "not-email"})
485
except ValidationError as e:
486
print(f"Validation failed: {e.message}")
487
```
488
489
### URI-based Schema Storage
490
491
```python
492
from jsonschema._utils import URIDict
493
from jsonschema import RefResolver, Draft7Validator
494
495
# Create URI-aware schema store
496
schema_store = URIDict()
497
schema_store['http://example.com/user.json'] = {
498
"type": "object",
499
"properties": {
500
"name": {"type": "string"},
501
"age": {"type": "integer", "minimum": 0}
502
}
503
}
504
505
schema_store['http://example.com/address.json'] = {
506
"type": "object",
507
"properties": {
508
"street": {"type": "string"},
509
"city": {"type": "string"},
510
"zipcode": {"type": "string", "pattern": r"^\d{5}$"}
511
}
512
}
513
514
# Main schema with references
515
main_schema = {
516
"type": "object",
517
"properties": {
518
"user": {"$ref": "http://example.com/user.json"},
519
"address": {"$ref": "http://example.com/address.json"}
520
}
521
}
522
523
# Create resolver with schema store
524
resolver = RefResolver(
525
base_uri="http://example.com/",
526
referrer=main_schema,
527
store=schema_store
528
)
529
530
validator = Draft7Validator(main_schema, resolver=resolver)
531
532
# Validate data with resolved references
533
data = {
534
"user": {"name": "Alice", "age": 30},
535
"address": {"street": "123 Main St", "city": "Anytown", "zipcode": "12345"}
536
}
537
538
validator.validate(data) # References are resolved automatically
539
```
540
541
### Validation Function Helpers
542
543
```python
544
from jsonschema._validators import (
545
type as type_validator,
546
minimum, maximum,
547
required
548
)
549
550
# These are the internal validation functions used by validators
551
# They follow the signature: validator_func(validator, value, instance, schema)
552
553
# Example of how validation functions work internally
554
class SimpleValidator:
555
def __init__(self, schema):
556
self.schema = schema
557
558
def validate_type(self, instance):
559
if "type" in self.schema:
560
# This simulates how type validation works internally
561
expected_type = self.schema["type"]
562
if expected_type == "string" and not isinstance(instance, str):
563
raise ValueError(f"Expected string, got {type(instance).__name__}")
564
elif expected_type == "integer" and not isinstance(instance, int):
565
raise ValueError(f"Expected integer, got {type(instance).__name__}")
566
567
def validate(self, instance):
568
self.validate_type(instance)
569
# Other validations would follow...
570
571
# Usage
572
validator = SimpleValidator({"type": "string"})
573
validator.validate("hello") # Valid
574
# validator.validate(123) # Would raise ValueError
575
```
576
577
## Types
578
579
```python { .api }
580
from typing import Any, Callable, IO, Iterable, Iterator, MutableMapping, Sequence
581
import argparse
582
import sys
583
584
# For type checking functions
585
from jsonschema._types import (
586
is_array, is_bool, is_integer, is_null, is_number,
587
is_object, is_string, is_any,
588
draft3_type_checker, draft4_type_checker,
589
draft6_type_checker, draft7_type_checker,
590
TypeChecker
591
)
592
593
# For CLI functions
594
from jsonschema.cli import main, parse_args
595
596
# For utility classes and functions
597
from jsonschema._utils import (
598
URIDict, find_additional_properties,
599
extras_msg, types_msg, unbool
600
)
601
602
# For reflection utilities
603
from jsonschema._reflect import namedAny
604
```