@@ -822,7 +822,8 @@ def resolve_all(self,
822822 loader .idx [metadata [identifer ]] = document
823823
824824 if checklinks :
825- self .validate_links (document , u"" )
825+ all_doc_ids = {} # type: Dict[Text, Text]
826+ self .validate_links (document , u"" , all_doc_ids )
826827
827828 return document , metadata
828829
@@ -877,8 +878,8 @@ def validate_scoped(self, field, link, docid):
877878 raise validate .ValidationException (
878879 "Field `%s` references unknown identifier `%s`, tried %s" % (field , link , ", " .join (tried )))
879880
880- def validate_link (self , field , link , docid ):
881- # type: (unicode, FieldType, unicode) -> FieldType
881+ def validate_link (self , field , link , docid , all_doc_ids ):
882+ # type: (unicode, FieldType, unicode, Dict[Text, Text] ) -> FieldType
882883 if field in self .nolinkcheck :
883884 return link
884885 if isinstance (link , (str , unicode )):
@@ -901,14 +902,14 @@ def validate_link(self, field, link, docid):
901902 errors = []
902903 for n , i in enumerate (link ):
903904 try :
904- link [n ] = self .validate_link (field , i , docid )
905+ link [n ] = self .validate_link (field , i , docid , all_doc_ids )
905906 except validate .ValidationException as v :
906907 errors .append (v )
907908 if bool (errors ):
908909 raise validate .ValidationException (
909910 "\n " .join ([unicode (e ) for e in errors ]))
910911 elif isinstance (link , CommentedMap ):
911- self .validate_links (link , docid )
912+ self .validate_links (link , docid , all_doc_ids )
912913 else :
913914 raise validate .ValidationException (
914915 "`%s` field is %s, expected string, list, or a dict."
@@ -924,8 +925,8 @@ def getid(self, d): # type: (Any) -> Optional[Text]
924925 return idd
925926 return None
926927
927- def validate_links (self , document , base_url ):
928- # type: (Union[CommentedMap, CommentedSeq, unicode, None], unicode) -> None
928+ def validate_links (self , document , base_url , all_doc_ids ):
929+ # type: (Union[CommentedMap, CommentedSeq, unicode, None], unicode, Dict[Text, Text] ) -> None
929930 docid = self .getid (document )
930931 if not docid :
931932 docid = base_url
@@ -939,7 +940,15 @@ def validate_links(self, document, base_url):
939940 for d in self .url_fields :
940941 sl = SourceLine (document , d , validate .ValidationException )
941942 if d in document and d not in self .identity_links :
942- document [d ] = self .validate_link (d , document [d ], docid )
943+ document [d ] = self .validate_link (d , document [d ], docid , all_doc_ids )
944+ for identifier in self .identifiers : # validate that each id is defined uniquely
945+ if identifier in document :
946+ sl = SourceLine (document , identifier , validate .ValidationException )
947+ if document [identifier ] in all_doc_ids and sl .makeLead () != all_doc_ids [document [identifier ]]:
948+ raise validate .ValidationException (
949+ "%s object %s `%s` previously defined" % (all_doc_ids [document [identifier ]], identifier , relname (document [identifier ]), ))
950+ else :
951+ all_doc_ids [document [identifier ]] = sl .makeLead ()
943952 except validate .ValidationException as v :
944953 errors .append (sl .makeError (unicode (v )))
945954 if hasattr (document , "iteritems" ):
@@ -952,7 +961,7 @@ def validate_links(self, document, base_url):
952961 for key , val in iterator :
953962 sl = SourceLine (document , key , validate .ValidationException )
954963 try :
955- self .validate_links (val , docid )
964+ self .validate_links (val , docid , all_doc_ids )
956965 except validate .ValidationException as v :
957966 if key not in self .nolinkcheck :
958967 docid2 = self .getid (val )
0 commit comments