from__future__importannotationsfromcopyimportdeepcopyfromtypingimportTYPE_CHECKING,Any,OptionalifTYPE_CHECKING:fromcollections.abcimportSequencedef_retrieve_ref(path:str,schema:dict)->dict:components=path.split("/")ifcomponents[0]!="#":msg=("ref paths are expected to be URI fragments, meaning they should start ""with #.")raiseValueError(msg)out=schemaforcomponentincomponents[1:]:ifcomponentinout:out=out[component]elifcomponent.isdigit()andint(component)inout:out=out[int(component)]else:msg=f"Reference '{path}' not found."raiseKeyError(msg)returndeepcopy(out)def_dereference_refs_helper(obj:Any,full_schema:dict[str,Any],skip_keys:Sequence[str],processed_refs:Optional[set[str]]=None,)->Any:ifprocessed_refsisNone:processed_refs=set()ifisinstance(obj,dict):obj_out={}fork,vinobj.items():ifkinskip_keys:obj_out[k]=velifk=="$ref":ifvinprocessed_refs:continueprocessed_refs.add(v)ref=_retrieve_ref(v,full_schema)full_ref=_dereference_refs_helper(ref,full_schema,skip_keys,processed_refs)processed_refs.remove(v)returnfull_refelifisinstance(v,(list,dict)):obj_out[k]=_dereference_refs_helper(v,full_schema,skip_keys,processed_refs)else:obj_out[k]=vreturnobj_outelifisinstance(obj,list):return[_dereference_refs_helper(el,full_schema,skip_keys,processed_refs)forelinobj]else:returnobjdef_infer_skip_keys(obj:Any,full_schema:dict,processed_refs:Optional[set[str]]=None)->list[str]:ifprocessed_refsisNone:processed_refs=set()keys=[]ifisinstance(obj,dict):fork,vinobj.items():ifk=="$ref":ifvinprocessed_refs:continueprocessed_refs.add(v)ref=_retrieve_ref(v,full_schema)keys.append(v.split("/")[1])keys+=_infer_skip_keys(ref,full_schema,processed_refs)elifisinstance(v,(list,dict)):keys+=_infer_skip_keys(v,full_schema,processed_refs)elifisinstance(obj,list):forelinobj:keys+=_infer_skip_keys(el,full_schema,processed_refs)returnkeys
[docs]defdereference_refs(schema_obj:dict,*,full_schema:Optional[dict]=None,skip_keys:Optional[Sequence[str]]=None,)->dict:"""Try to substitute $refs in JSON Schema. Args: schema_obj: The schema object to dereference. full_schema: The full schema object. Defaults to None. skip_keys: The keys to skip. Defaults to None. Returns: The dereferenced schema object. """full_schema=full_schemaorschema_objskip_keys=(skip_keysifskip_keysisnotNoneelse_infer_skip_keys(schema_obj,full_schema))return_dereference_refs_helper(schema_obj,full_schema,skip_keys)