Skip to content

Commit c509a07

Browse files
authored
Merge pull request #34 from common-workflow-language/unscoped_ids
Unscoped ids
2 parents ef27301 + f857e9d commit c509a07

File tree

7 files changed

+151
-18
lines changed

7 files changed

+151
-18
lines changed

schema_salad/jsonld_context.py

+49
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,52 @@ def salad_to_jsonld_context(j, schema_ctx):
175175
process_type(t, g, context, defaultBase, namespaces, defaultPrefix)
176176

177177
return (context, g)
178+
179+
def fix_jsonld_ids(obj, ids):
180+
# type: (Union[Dict[unicode, Any], List[Dict[unicode, Any]]], List[unicode]) -> None
181+
if isinstance(obj, dict):
182+
for i in ids:
183+
if i in obj:
184+
obj["@id"] = obj[i]
185+
for v in obj.values():
186+
fix_jsonld_ids(v, ids)
187+
if isinstance(obj, list):
188+
for entry in obj:
189+
fix_jsonld_ids(entry, ids)
190+
191+
def makerdf(workflow, wf, ctx):
192+
# type: (Union[str, unicode], Union[List[Dict[unicode, Any]], Dict[unicode, Any]], Loader.ContextType) -> Graph
193+
prefixes = {}
194+
idfields = []
195+
for k,v in ctx.iteritems():
196+
if isinstance(v, dict):
197+
url = v["@id"]
198+
else:
199+
url = v
200+
if url == "@id":
201+
idfields.append(k)
202+
doc_url, frg = urlparse.urldefrag(url)
203+
if "/" in frg:
204+
p, _ = frg.split("/")
205+
prefixes[p] = u"%s#%s/" % (doc_url, p)
206+
207+
if isinstance(wf, list):
208+
wf = {
209+
"@context": ctx,
210+
"@graph": wf
211+
}
212+
else:
213+
wf["@context"] = ctx
214+
215+
fix_jsonld_ids(wf, idfields)
216+
217+
g = Graph().parse(data=json.dumps(wf), format='json-ld', location=workflow)
218+
219+
# Bug in json-ld loader causes @id fields to be added to the graph
220+
for s,p,o in g.triples((None, URIRef("@id"), None)):
221+
g.remove((s, p, o))
222+
223+
for k2,v2 in prefixes.iteritems():
224+
g.namespace_manager.bind(k2, v2)
225+
226+
return g

schema_salad/main.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@
2323

2424

2525
def printrdf(workflow, wf, ctx, sr):
26-
# type: (str, Union[List, Dict[Any, Any], str, unicode], Dict[unicode, Any], str) -> None
27-
g = Graph().parse(data=json.dumps(wf), format='json-ld',
28-
location=workflow, context=ctx)
26+
# type: (str, Union[List[Dict[unicode, Any]], Dict[unicode, Any]], Dict[unicode, Any], str) -> None
27+
g = jsonld_context.makerdf(workflow, wf, ctx)
2928
print(g.serialize(format=sr))
3029

3130

@@ -210,8 +209,12 @@ def main(argsl=None): # type: (List[str]) -> int
210209

211210
# Optionally convert the document to RDF
212211
if args.print_rdf:
213-
printrdf(args.document, document, schema_ctx, args.rdf_serializer)
214-
return 0
212+
if isinstance(document, (dict, list)):
213+
printrdf(args.document, document, schema_ctx, args.rdf_serializer)
214+
return 0
215+
else:
216+
print("Document must be a dictionary or list.")
217+
return 1
215218

216219
if args.print_metadata:
217220
print(json.dumps(doc_metadata, indent=4))

schema_salad/metaschema/metaschema_base.yml

+13-10
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,19 @@ $graph:
4343
type: record
4444
doc: A field of a record.
4545
fields:
46-
- name: name
46+
name:
4747
type: string
4848
jsonldPredicate: "@id"
4949
doc: |
5050
The name of the field
5151
52-
- name: doc
52+
doc:
5353
type: string?
5454
doc: |
5555
A documentation string for this field
5656
jsonldPredicate: "sld:doc"
5757

58-
- name: type
58+
type:
5959
type:
6060
- PrimitiveType
6161
- RecordSchema
@@ -81,7 +81,7 @@ $graph:
8181
- name: RecordSchema
8282
type: record
8383
fields:
84-
- name: type
84+
type:
8585
doc: "Must be `record`"
8686
type:
8787
name: Record_symbol
@@ -93,9 +93,12 @@ $graph:
9393
_type: "@vocab"
9494
typeDSL: true
9595
refScope: 2
96-
- name: "fields"
96+
fields:
9797
type: RecordField[]?
98-
jsonldPredicate: "sld:fields"
98+
jsonldPredicate:
99+
_id: sld:fields
100+
mapSubject: name
101+
mapPredicate: type
99102
doc: "Defines the fields of the record."
100103

101104

@@ -104,7 +107,7 @@ $graph:
104107
doc: |
105108
Define an enumerated type.
106109
fields:
107-
- name: type
110+
type:
108111
doc: "Must be `enum`"
109112
type:
110113
name: Enum_symbol
@@ -116,7 +119,7 @@ $graph:
116119
_type: "@vocab"
117120
typeDSL: true
118121
refScope: 2
119-
- name: "symbols"
122+
symbols:
120123
type: string[]
121124
jsonldPredicate:
122125
_id: "sld:symbols"
@@ -128,7 +131,7 @@ $graph:
128131
- name: ArraySchema
129132
type: record
130133
fields:
131-
- name: type
134+
type:
132135
doc: "Must be `array`"
133136
type:
134137
name: Array_symbol
@@ -140,7 +143,7 @@ $graph:
140143
_type: "@vocab"
141144
typeDSL: true
142145
refScope: 2
143-
- name: items
146+
items:
144147
type:
145148
- PrimitiveType
146149
- RecordSchema

schema_salad/ref_resolver.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,9 @@ def expand_url(self, url, base_url, scoped_id=False, vocab_term=False, scoped_re
135135
frg = splitbase.fragment + u"/" + split.path
136136
else:
137137
frg = split.path
138+
pt = splitbase.path if splitbase.path else "/"
138139
url = urlparse.urlunsplit(
139-
(splitbase.scheme, splitbase.netloc, splitbase.path, splitbase.query, frg))
140+
(splitbase.scheme, splitbase.netloc, pt, splitbase.query, frg))
140141
elif scoped_ref is not None and not split.fragment:
141142
pass
142143
else:

schema_salad/schema.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,11 @@ def get_metaschema():
9797
"@type": "@id",
9898
"refScope": 1
9999
},
100-
"fields": "sld:fields",
100+
"fields": {
101+
"@id": "sld:fields",
102+
"mapSubject": "name",
103+
"mapPredicate": "type"
104+
},
101105
"float": "http://www.w3.org/2001/XMLSchema#float",
102106
"identity": "https://w3id.org/cwl/salad#JsonldPredicate/identity",
103107
"int": "http://www.w3.org/2001/XMLSchema#int",

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
extras_require = {} # TODO: to be removed when the above is added
4242

4343
setup(name='schema-salad',
44-
version='1.12',
44+
version='1.13',
4545
description='Schema Annotations for Linked Avro Data (SALAD)',
4646
long_description=open(README).read(),
4747
author='Common workflow language working group',

tests/test_examples.py

+73
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
import schema_salad.ref_resolver
33
import schema_salad.main
44
import schema_salad.schema
5+
from schema_salad.jsonld_context import makerdf
56
import rdflib
67
import ruamel.yaml as yaml
8+
import json
9+
710
try:
811
from ruamel.yaml import CSafeLoader as SafeLoader
912
except ImportError:
@@ -249,5 +252,75 @@ def test_typedsl_ref(self):
249252
ra, _ = ldr.resolve_all({"type": "File[]?"}, "")
250253
self.assertEqual({'type': ['null', {'items': 'File', 'type': 'array'}]}, ra)
251254

255+
def test_scoped_id(self):
256+
ldr = schema_salad.ref_resolver.Loader({})
257+
ctx = {
258+
"id": "@id",
259+
"location": {
260+
"@id": "@id",
261+
"@type": "@id"
262+
},
263+
"bar": "http://example.com/bar",
264+
"ex": "http://example.com/"
265+
}
266+
ldr.add_context(ctx)
267+
268+
ra, _ = ldr.resolve_all({
269+
"id": "foo",
270+
"bar": {
271+
"id": "baz"
272+
}
273+
}, "http://example.com")
274+
self.assertEqual({'id': 'http://example.com/#foo',
275+
'bar': {
276+
'id': 'http://example.com/#foo/baz'},
277+
}, ra)
278+
279+
g = makerdf(None, ra, ctx)
280+
print(g.serialize(format="n3"))
281+
282+
ra, _ = ldr.resolve_all({
283+
"location": "foo",
284+
"bar": {
285+
"location": "baz"
286+
}
287+
}, "http://example.com", checklinks=False)
288+
self.assertEqual({'location': 'http://example.com/foo',
289+
'bar': {
290+
'location': 'http://example.com/baz'},
291+
}, ra)
292+
293+
g = makerdf(None, ra, ctx)
294+
print(g.serialize(format="n3"))
295+
296+
ra, _ = ldr.resolve_all({
297+
"id": "foo",
298+
"bar": {
299+
"location": "baz"
300+
}
301+
}, "http://example.com", checklinks=False)
302+
self.assertEqual({'id': 'http://example.com/#foo',
303+
'bar': {
304+
'location': 'http://example.com/baz'},
305+
}, ra)
306+
307+
g = makerdf(None, ra, ctx)
308+
print(g.serialize(format="n3"))
309+
310+
ra, _ = ldr.resolve_all({
311+
"location": "foo",
312+
"bar": {
313+
"id": "baz"
314+
}
315+
}, "http://example.com", checklinks=False)
316+
self.assertEqual({'location': 'http://example.com/foo',
317+
'bar': {
318+
'id': 'http://example.com/#baz'},
319+
}, ra)
320+
321+
g = makerdf(None, ra, ctx)
322+
print(g.serialize(format="n3"))
323+
324+
252325
if __name__ == '__main__':
253326
unittest.main()

0 commit comments

Comments
 (0)