8
8
import inflection
9
9
import jsonschema
10
10
import six
11
- from jsonschema import Draft4Validator
12
-
13
11
import python_jsonschema_objects .classbuilder as classbuilder
14
12
import python_jsonschema_objects .markdown_support
15
13
import python_jsonschema_objects .util
16
14
from python_jsonschema_objects .validators import ValidationError
15
+ from typing import Optional
16
+
17
+ from jsonschema_specifications import REGISTRY as SPECIFICATIONS
18
+ from referencing import Registry , Resource
19
+ import referencing .typing
20
+ import referencing .jsonschema
21
+ import referencing .retrieval
17
22
18
23
19
24
logger = logging .getLogger (__name__ )
23
28
FILE = __file__
24
29
25
30
SUPPORTED_VERSIONS = (
26
- "http://json-schema.org/draft-03/schema# " ,
27
- "http://json-schema.org/draft-04/schema# " ,
31
+ "http://json-schema.org/draft-03/schema" ,
32
+ "http://json-schema.org/draft-04/schema" ,
28
33
)
29
34
30
35
31
36
class ObjectBuilder (object ):
32
- def __init__ (self , schema_uri , resolved = {}, resolver = None , validatorClass = None ):
33
- self .mem_resolved = resolved
34
-
37
+ def __init__ (
38
+ self ,
39
+ schema_uri ,
40
+ resolved = {},
41
+ registry : Optional [referencing .Registry ] = None ,
42
+ resolver : Optional [referencing .typing .Retrieve ] = None ,
43
+ specification_uri : str = "http://json-schema.org/draft-04/schema" ,
44
+ ):
35
45
if isinstance (schema_uri , six .string_types ):
36
46
uri = os .path .normpath (schema_uri )
37
47
self .basedir = os .path .dirname (uri )
@@ -44,7 +54,7 @@ def __init__(self, schema_uri, resolved={}, resolver=None, validatorClass=None):
44
54
45
55
if (
46
56
"$schema" in self .schema
47
- and self .schema ["$schema" ] not in SUPPORTED_VERSIONS
57
+ and self .schema ["$schema" ]. rstrip ( "#" ) not in SUPPORTED_VERSIONS
48
58
):
49
59
warnings .warn (
50
60
"Schema version {} not recognized. Some "
@@ -53,15 +63,78 @@ def __init__(self, schema_uri, resolved={}, resolver=None, validatorClass=None):
53
63
)
54
64
)
55
65
56
- self .resolver = resolver or jsonschema .RefResolver .from_schema (self .schema )
57
- self .resolver .handlers .update (
58
- {"file" : self .relative_file_resolver , "memory" : self .memory_resolver }
59
- )
66
+ if registry is not None :
67
+ if not isinstance (registry , referencing .Registry ):
68
+ raise TypeError ("registry must be a Registry instance" )
69
+
70
+ if resolver is not None :
71
+ raise AttributeError (
72
+ "Cannot specify both registry and resolver. If you provide your own registry, pass the resolver directly to that"
73
+ )
74
+ self .registry = registry
75
+ else :
76
+ if resolver is not None :
77
+
78
+ def file_and_memory_handler (uri ):
79
+ if uri .startswith ("file:" ):
80
+ return Resource .from_contents (self .relative_file_resolver (uri ))
81
+ return resolver (uri )
82
+
83
+ self .registry = Registry (retrieve = file_and_memory_handler )
84
+ else :
85
+
86
+ def file_and_memory_handler (uri ):
87
+ if uri .startswith ("file:" ):
88
+ return Resource .from_contents (self .relative_file_resolver (uri ))
89
+ raise RuntimeError (
90
+ "No remote resource resolver provided. Cannot resolve {}" .format (
91
+ uri
92
+ )
93
+ )
60
94
61
- validatorClass = validatorClass or Draft4Validator
62
- meta_validator = validatorClass (validatorClass .META_SCHEMA )
95
+ self .registry = Registry (retrieve = file_and_memory_handler )
96
+
97
+ if len (resolved ) > 0 :
98
+ warnings .warn (
99
+ "Use of 'memory:' URIs is deprecated. Provide a registry with properly resolved references "
100
+ "if you want to resolve items externally." ,
101
+ DeprecationWarning ,
102
+ )
103
+ for uri , contents in resolved .items ():
104
+ self .registry = self .registry .with_resource (
105
+ "memory:" + uri ,
106
+ referencing .Resource .from_contents (contents , specification_uri ),
107
+ )
108
+
109
+ if "$schema" not in self .schema :
110
+ warnings .warn ("Schema version not specified. Defaulting to draft4" )
111
+ updated = {"$schema" : specification_uri }
112
+ updated .update (self .schema )
113
+ self .schema = updated
114
+
115
+ schema = Resource .from_contents (self .schema )
116
+ if schema .id () is None :
117
+ warnings .warn ("Schema id not specified. Defaulting to 'self'" )
118
+ updated = {"$id" : "self" , "id" : "self" }
119
+ updated .update (self .schema )
120
+ self .schema = updated
121
+ schema = Resource .from_contents (self .schema )
122
+
123
+ self .registry = self .registry .with_resource ("" , schema )
124
+ self .resolver = self .registry .resolver ()
125
+
126
+ if specification_uri is not None :
127
+ validatorClass = jsonschema .validators .validator_for (
128
+ {"$schema" : specification_uri }
129
+ )
130
+ else :
131
+ validatorClass = jsonschema .validators .validator_for (self .schema )
132
+
133
+ meta_validator = validatorClass (
134
+ validatorClass .META_SCHEMA , registry = self .registry
135
+ )
63
136
meta_validator .validate (self .schema )
64
- self .validator = validatorClass (self .schema , resolver = self .resolver )
137
+ self .validator = validatorClass (self .schema , registry = self .registry )
65
138
66
139
self ._classes = None
67
140
self ._resolved = None
@@ -88,9 +161,6 @@ def get_class(self, uri):
88
161
self ._classes = self .build_classes ()
89
162
return self ._resolved .get (uri , None )
90
163
91
- def memory_resolver (self , uri ):
92
- return self .mem_resolved [uri [7 :]]
93
-
94
164
def relative_file_resolver (self , uri ):
95
165
path = os .path .join (self .basedir , uri [8 :])
96
166
with codecs .open (path , "r" , "utf-8" ) as fin :
@@ -129,10 +199,11 @@ def build_classes(self, strict=False, named_only=False, standardize_names=True):
129
199
kw = {"strict" : strict }
130
200
builder = classbuilder .ClassBuilder (self .resolver )
131
201
for nm , defn in six .iteritems (self .schema .get ("definitions" , {})):
202
+ resolved = self .resolver .lookup ("#/definitions/" + nm )
132
203
uri = python_jsonschema_objects .util .resolve_ref_uri (
133
- self .resolver .resolution_scope , "#/definitions/" + nm
204
+ self .resolver ._base_uri , "#/definitions/" + nm
134
205
)
135
- builder .construct (uri , defn , ** kw )
206
+ builder .construct (uri , resolved . contents , ** kw )
136
207
137
208
if standardize_names :
138
209
name_transform = lambda t : inflection .camelize (
0 commit comments