@@ -94,6 +94,7 @@ def __init__(self, ctx, schemagraph=None, foreign_properties=None,
94
94
self .cache = {}
95
95
96
96
self .url_fields = None # type: Set[str]
97
+ self .scoped_ref_fields = None # type: Set[str]
97
98
self .vocab_fields = None # type: Set[str]
98
99
self .identifiers = None # type: Set[str]
99
100
self .identity_links = None # type: Set[str]
@@ -186,6 +187,7 @@ def add_context(self, newcontext, baseuri=""):
186
187
"Refreshing context that already has stuff in it" )
187
188
188
189
self .url_fields = set ()
190
+ self .scoped_ref_fields = set ()
189
191
self .vocab_fields = set ()
190
192
self .identifiers = set ()
191
193
self .identity_links = set ()
@@ -206,6 +208,8 @@ def add_context(self, newcontext, baseuri=""):
206
208
self .identity_links .add (key )
207
209
elif isinstance (value , dict ) and value .get ("@type" ) == "@id" :
208
210
self .url_fields .add (key )
211
+ if value .get ("scopedRef" , False ):
212
+ self .scoped_ref_fields .add (key )
209
213
if value .get ("identity" , False ):
210
214
self .identity_links .add (key )
211
215
elif isinstance (value , dict ) and value .get ("@type" ) == "@vocab" :
@@ -235,7 +239,7 @@ def add_context(self, newcontext, baseuri=""):
235
239
_logger .debug ("vocab_fields is %s" , self .vocab_fields )
236
240
_logger .debug ("vocab is %s" , self .vocab )
237
241
238
- def resolve_ref (self , ref , base_url = None ):
242
+ def resolve_ref (self , ref , base_url = None , toplevel = True ):
239
243
# type: (Union[Dict[str, Any], str, unicode], Union[str, unicode]) -> Tuple[Union[Dict[str, Any], str, unicode], Dict[str, Any]]
240
244
base_url = base_url or 'file://%s/' % os .path .abspath ('.' )
241
245
@@ -297,7 +301,7 @@ def resolve_ref(self, ref, base_url=None):
297
301
doc = self .fetch (doc_url )
298
302
299
303
# Recursively expand urls and resolve directives
300
- obj , metadata = self .resolve_all (doc if doc else obj , doc_url )
304
+ obj , metadata = self .resolve_all (doc if doc else obj , doc_url , toplevel = toplevel )
301
305
302
306
# Requested reference should be in the index now, otherwise it's a bad
303
307
# reference
@@ -318,7 +322,7 @@ def resolve_ref(self, ref, base_url=None):
318
322
except TypeError :
319
323
return obj , metadata
320
324
321
- def resolve_all (self , document , base_url , file_base = None ):
325
+ def resolve_all (self , document , base_url , file_base = None , toplevel = True ):
322
326
# type: (Any, Union[str, unicode], Union[str, unicode]) -> Tuple[Any, Dict[str, Any]]
323
327
loader = self
324
328
metadata = {} # type: Dict[str, Any]
@@ -328,7 +332,7 @@ def resolve_all(self, document, base_url, file_base=None):
328
332
if isinstance (document , dict ):
329
333
# Handle $import and $include
330
334
if ('$import' in document or '$include' in document ):
331
- return self .resolve_ref (document , file_base )
335
+ return self .resolve_ref (document , base_url = file_base , toplevel = toplevel )
332
336
elif isinstance (document , list ):
333
337
pass
334
338
else :
@@ -364,7 +368,7 @@ def resolve_all(self, document, base_url, file_base=None):
364
368
if "$graph" in document :
365
369
metadata = _copy_dict_without_key (document , "$graph" )
366
370
document = document ["$graph" ]
367
- metadata , _ = loader .resolve_all (metadata , base_url , file_base )
371
+ metadata , _ = loader .resolve_all (metadata , base_url , file_base = file_base , toplevel = False )
368
372
369
373
if isinstance (document , dict ):
370
374
for idmapField in loader .idmap :
@@ -412,6 +416,8 @@ def resolve_all(self, document, base_url, file_base=None):
412
416
del document [d ]
413
417
414
418
for d in loader .url_fields :
419
+ if d in self .scoped_ref_fields :
420
+ continue
415
421
if d in document :
416
422
if isinstance (document [d ], basestring ):
417
423
document [d ] = loader .expand_url (
@@ -427,7 +433,7 @@ def resolve_all(self, document, base_url, file_base=None):
427
433
try :
428
434
for key , val in document .items ():
429
435
document [key ], _ = loader .resolve_all (
430
- val , base_url , file_base )
436
+ val , base_url , file_base = file_base , toplevel = False )
431
437
except validate .ValidationException as v :
432
438
_logger .debug ("loader is %s" , id (loader ))
433
439
raise validate .ValidationException ("(%s) (%s) Validation error in field %s:\n %s" % (
@@ -439,7 +445,7 @@ def resolve_all(self, document, base_url, file_base=None):
439
445
while i < len (document ):
440
446
val = document [i ]
441
447
if isinstance (val , dict ) and "$import" in val :
442
- l , _ = loader .resolve_ref (val , file_base )
448
+ l , _ = loader .resolve_ref (val , base_url = file_base , toplevel = False )
443
449
if isinstance (l , list ):
444
450
del document [i ]
445
451
for item in aslist (l ):
@@ -450,7 +456,7 @@ def resolve_all(self, document, base_url, file_base=None):
450
456
i += 1
451
457
else :
452
458
document [i ], _ = loader .resolve_all (
453
- val , base_url , file_base )
459
+ val , base_url , file_base = file_base , toplevel = False )
454
460
i += 1
455
461
except validate .ValidationException as v :
456
462
raise validate .ValidationException ("(%s) (%s) Validation error in position %i:\n %s" % (
@@ -463,6 +469,9 @@ def resolve_all(self, document, base_url, file_base=None):
463
469
metadata [identifer ], base_url , scoped = True )
464
470
loader .idx [metadata [identifer ]] = document
465
471
472
+ if toplevel :
473
+ self .validate_links (document , "" )
474
+
466
475
return document , metadata
467
476
468
477
def fetch_text (self , url ):
@@ -522,36 +531,51 @@ def check_file(self, fn): # type: (Union[str, unicode]) -> bool
522
531
else :
523
532
return False
524
533
525
- def validate_link (self , field , link ):
534
+ def validate_link (self , field , link , docid ):
526
535
# type: (str, Union[str, unicode, List[str], Dict[str, Any]]) -> bool
527
536
if field in self .nolinkcheck :
528
- return True
537
+ return link
529
538
if isinstance (link , (str , unicode )):
530
539
if field in self .vocab_fields :
531
540
if link not in self .vocab and link not in self .idx and link not in self .rvocab :
532
541
if not self .check_file (link ):
533
542
raise validate .ValidationException (
534
543
"Field `%s` contains undefined reference to `%s`" % (field , link ))
535
544
elif link not in self .idx and link not in self .rvocab :
536
- if not self .check_file (link ):
545
+ if field in self .scoped_ref_fields :
546
+ split = urlparse .urlsplit (docid )
547
+ sp = split .fragment .split ("/" )
548
+ while len (sp ) > 0 :
549
+ sp .pop ()
550
+ sp .append (link )
551
+ url = urlparse .urlunsplit (
552
+ (split .scheme , split .netloc , split .path , split .query , "/" .join (sp )))
553
+ if url in self .idx :
554
+ print link , "is" , url
555
+ return url
556
+ else :
557
+ sp .pop ()
558
+ raise validate .ValidationException (
559
+ "Field `%s` contains undefined reference to `%s`" % (field , link ))
560
+ elif not self .check_file (link ):
537
561
raise validate .ValidationException (
538
562
"Field `%s` contains undefined reference to `%s`" % (field , link ))
539
563
elif isinstance (link , list ):
540
564
errors = []
541
- for i in link :
565
+ for n , i in enumerate ( link ) :
542
566
try :
543
- self .validate_link (field , i )
567
+ link [ n ] = self .validate_link (field , i , docid )
544
568
except validate .ValidationException as v :
545
569
errors .append (v )
546
570
if errors :
547
571
raise validate .ValidationException (
548
572
"\n " .join ([str (e ) for e in errors ]))
549
573
elif isinstance (link , dict ):
550
- self .validate_links (link )
574
+ self .validate_links (link , docid )
551
575
else :
552
576
raise validate .ValidationException ("Link must be a str, unicode, "
553
577
"list, or a dict." )
554
- return True
578
+ return link
555
579
556
580
def getid (self , d ): # type: (Any) -> Union[basestring, None]
557
581
if isinstance (d , dict ):
@@ -561,10 +585,10 @@ def getid(self, d): # type: (Any) -> Union[basestring, None]
561
585
return d [i ]
562
586
return None
563
587
564
- def validate_links (self , document ): # type: (Any) -> None
588
+ def validate_links (self , document , base_url ): # type: (Any) -> None
565
589
docid = self .getid (document )
566
- if docid is None :
567
- docid = ""
590
+ if not docid :
591
+ docid = base_url
568
592
569
593
errors = []
570
594
iterator = None # type: Any
@@ -573,26 +597,26 @@ def validate_links(self, document): # type: (Any) -> None
573
597
elif isinstance (document , dict ):
574
598
try :
575
599
for d in self .url_fields :
576
- if d not in self . identity_links and d in document :
577
- self .validate_link (d , document [d ])
600
+ if d in document and d not in self . identity_links :
601
+ document [ d ] = self .validate_link (d , document [d ], docid )
578
602
except validate .ValidationException as v :
579
603
errors .append (v )
580
604
if hasattr (document , "iteritems" ):
581
605
iterator = document .iteritems ()
582
606
else :
583
607
iterator = document .items ()
584
608
else :
585
- return
609
+ return document
586
610
587
611
for key , val in iterator :
588
612
try :
589
- self .validate_links (val )
613
+ document [ key ] = self .validate_links (val , docid )
590
614
except validate .ValidationException as v :
591
615
if key not in self .nolinkcheck :
592
- docid = self .getid (val )
593
- if docid :
616
+ docid2 = self .getid (val )
617
+ if docid2 :
594
618
errors .append (validate .ValidationException (
595
- "While checking object `%s`\n %s" % (docid , validate .indent (str (v )))))
619
+ "While checking object `%s`\n %s" % (docid2 , validate .indent (str (v )))))
596
620
else :
597
621
if isinstance (key , basestring ):
598
622
errors .append (validate .ValidationException (
@@ -607,7 +631,7 @@ def validate_links(self, document): # type: (Any) -> None
607
631
"\n " .join ([str (e ) for e in errors ]))
608
632
else :
609
633
raise errors [0 ]
610
- return
634
+ return document
611
635
612
636
613
637
def _copy_dict_without_key (from_dict , filtered_key ):
0 commit comments