Skip to content

Commit c6d4a7b

Browse files
author
Peter Amstutz
committed
Reworking refScope to be fixed instead of search based.
1 parent ae0ef4e commit c6d4a7b

File tree

3 files changed

+49
-20
lines changed

3 files changed

+49
-20
lines changed

schema_salad/metaschema/metaschema.yml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,17 @@ $graph:
139139
the item is transformed to a JSON object with the key assigned to the
140140
field specified by `mapSubject` and the value assigned to the field
141141
specified by `mapPredicate`.
142-
- name: scopedRef
143-
type: ["null", boolean]
142+
- name: refScope
143+
type:
144+
- "null"
145+
- int
144146
doc: |
145-
If the field contains a relative reference, it must be resolved by
146-
searching for valid document references in each successive parent
147-
scope. For example, a reference of "foo" in the context "#foo/bar/baz"
148-
will first check for the existence of "#foo/bar/baz/foo", followed
149-
by "#foo/bar/foo", then "#foo/foo" and then finally "#foo". The first
150-
valid URI in the search order shall be used as the fully resolved value
151-
of the identifier.
147+
Remove the specified number of layers from the containing identifer
148+
scope and join with the field value to yield the identifier. For
149+
example, an identifer scope of `#foo/bar/baz`, `refScope: 0` and
150+
identifier `quux` will yield `#foo/bar/baz/quux`. `refScope: 1` will
151+
yield `#foo/bar/quux`, `refScope: 2` will yield `#foo/quux` and so
152+
forth.
152153
153154
- name: SpecializeDef
154155
type: record

schema_salad/ref_resolver.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def __init__(self, ctx, schemagraph=None, foreign_properties=None,
9494
self.cache = {}
9595

9696
self.url_fields = None # type: Set[str]
97-
self.scoped_ref_fields = None # type: Set[str]
97+
self.scoped_ref_fields = None # type: Dict[unicode, unicode]
9898
self.vocab_fields = None # type: Set[str]
9999
self.identifiers = None # type: Set[str]
100100
self.identity_links = None # type: Set[str]
@@ -187,7 +187,7 @@ def add_context(self, newcontext, baseuri=""):
187187
"Refreshing context that already has stuff in it")
188188

189189
self.url_fields = set()
190-
self.scoped_ref_fields = set()
190+
self.scoped_ref_fields = {}
191191
self.vocab_fields = set()
192192
self.identifiers = set()
193193
self.identity_links = set()
@@ -208,8 +208,8 @@ def add_context(self, newcontext, baseuri=""):
208208
self.identity_links.add(key)
209209
elif isinstance(value, dict) and value.get("@type") == "@id":
210210
self.url_fields.add(key)
211-
if value.get("scopedRef", False):
212-
self.scoped_ref_fields.add(key)
211+
if value.get("refScope", False):
212+
self.scoped_ref_fields[key] = value["refScope"]
213213
if value.get("identity", False):
214214
self.identity_links.add(key)
215215
elif isinstance(value, dict) and value.get("@type") == "@vocab":
@@ -376,7 +376,8 @@ def resolve_all(self, document, base_url, file_base=None, checklinks=True):
376376
"$import" not in document[idmapField] and
377377
"$include" not in document[idmapField]):
378378
ls = []
379-
for k, v in document[idmapField].items():
379+
for k in sorted(document[idmapField].keys()):
380+
v = document[idmapField][k]
380381
if not isinstance(v, dict):
381382
if idmapField in loader.mapPredicate:
382383
v = {loader.mapPredicate[idmapField]: v}
@@ -547,10 +548,16 @@ def validate_link(self, field, link, docid):
547548
if field in self.scoped_ref_fields:
548549
split = urlparse.urlsplit(docid)
549550
sp = split.fragment.split("/")
551+
print field, self.scoped_ref_fields[field], sp
552+
if self.scoped_ref_fields[field] in ("grandparent"):
553+
sp.pop()
554+
if self.scoped_ref_fields[field] in ("parent", "grandparent"):
555+
sp.pop()
550556
while True:
551557
sp.append(str(link))
552558
url = urlparse.urlunsplit(
553559
(split.scheme, split.netloc, split.path, split.query, "/".join(sp)))
560+
print "trying", url, "field", field
554561
if url in self.idx:
555562
return url
556563
sp.pop()

tests/test_examples.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,16 +111,20 @@ def test_scoped_ref(self):
111111
ldr.add_context({
112112
"scatter": {
113113
"@type": "@id",
114-
"scopedRef": True,
114+
"refScope": 0,
115115
},
116116
"source": {
117117
"@type": "@id",
118-
"scopedRef": True,
118+
"refScope": 2,
119119
},
120120
"in": {
121121
"mapSubject": "id",
122122
"mapPredicate": "source"
123123
},
124+
"out": {
125+
"@type": "@id",
126+
"identity": True
127+
},
124128
"inputs": {
125129
"mapSubject": "id",
126130
"mapPredicate": "type"
@@ -137,23 +141,40 @@ def test_scoped_ref(self):
137141
"steps": {
138142
"step1": {
139143
"in": {
140-
"echo_in": "inp"
144+
"inp": "inp"
145+
},
146+
"out": ["out"],
147+
"scatter": "inp"
148+
},
149+
"step2": {
150+
"in": {
151+
"inp": "step1/out"
141152
},
142-
"scatter": "echo_in"
153+
"scatter": "inp"
143154
}
144155
}
145156
}, "http://example2.com/")
146157

158+
print yaml.dump(ra)
159+
147160
self.assertEquals({'inputs': [{
148161
'id': 'http://example2.com/#inp',
149162
'type': 'string'
150163
}],
151164
'steps': [{
152165
'id': 'http://example2.com/#step1',
153-
'scatter': 'http://example2.com/#step1/echo_in',
166+
'scatter': 'http://example2.com/#step1/inp',
154167
'in': [{
155-
'id': 'http://example2.com/#step1/echo_in',
168+
'id': 'http://example2.com/#step1/inp',
156169
'source': 'http://example2.com/#inp'
170+
}],
171+
"out": ["http://example2.com/#step1/out"],
172+
}, {
173+
'id': 'http://example2.com/#step2',
174+
'scatter': 'http://example2.com/#step2/inp',
175+
'in': [{
176+
'id': 'http://example2.com/#step2/inp',
177+
'source': 'http://example2.com/#step1/out'
157178
}]
158179
}]
159180
}, ra)

0 commit comments

Comments
 (0)