def resolve_remote_with_uri( self, doc: Any, parts_idx: int) -> Tuple[Optional[URI], Optional[Any]]: """Defer resolution of references to a new RefPointer. :param doc: document element. :param parts_idx: index of the reference part reached. :return: tuple indicating (1) if doc was a ref (the ref URI returned) and (2) what that ref value was. """ if not (isinstance(doc, abc.Mapping) and isinstance(doc.get("$ref"), str)): return None, None remote_uri = self.uri.relative(doc["$ref"]).get( *[parse_segment(part) for part in self.parts[parts_idx + 1:]]) resolved_remote_uri, value = resolve_uri_to_urivalue_pair(remote_uri) return resolved_remote_uri, value
def _materialize_recursive( conf: MaterializeConf, repeats: Dict[URI, _RepeatCache], pointer: str, item: Any, ) -> Any: """Recursive function for materializing RefDict/RefList objects. Keeps track of previously seen items, and stores a reference on repeats. Cyclical references are avoided this way, and must be added in afterwards (see `materialize`). :param conf: `MaterializeConf` object specifying any transformations to perform. :param repeats: Shared mutable dictionary for keeping track of items which appear multiple times (sometimes in the same path). :param pointer: Pointer of the current item relative to the first call. :param item: The data object to operate on. :return: The materialized version of `item`, or `None` if this URI has already been traversed elsewhere. """ # End-cases if not isinstance(item, (RefDict, RefList)): return conf.value_map(item) if item.uri in repeats: repeats[item.uri][1].add(JsonPointer(pointer)) return None # Keep a record of walking this URI and recurse through the # contained items. repeats[item.uri] = _RepeatCache(source=JsonPointer(pointer), repeats=set()) recur = lambda seg, data: _materialize_recursive( conf, repeats, _next_path(pointer)(parse_segment(seg)), data) if isinstance(item, RefList): return [recur(str(idx), subitem) for idx, subitem in enumerate(item)] return { **conf.label(item), **{ key: recur(key, value) for key, value in item.items() if conf.match_key(key) }, }
def __getitem__(self, key: str): """Propagate ref resolution behaviour to nested objects.""" item = super().__getitem__(key) uri = self.uri.get(parse_segment(key)) return propagate(uri, item)
def recur(seg, data): return _materialize_recursive( conf, repeats, _next_path(pointer)(parse_segment(seg)), data )