예제 #1
0
    def _dive(self,
              ref: str,
              path: Path,
              visited_refs: ty.Optional[VisitedRefs] = None,
              ref_resolver: ty.Optional[RefResolver] = None,
              registry: ty.Optional[Registry] = None,
              **context: ty.Any) -> ty.Any:
        visited_refs = visited_refs or set()

        assert ref_resolver is not None
        assert registry is not None

        try:
            with ref_resolver.resolving(ref) as target:
                target_path = Path(ref_resolver.resolution_scope)

                if target_path in visited_refs:
                    raise RecursiveReferenceError()

                result = registry.get(target_path)

                if result is Bad:
                    raise SchemaError(
                        Error(path, self.messages['bad_reference']))

                elif result is not None:
                    return result

                proxy = ObjectProxy(Dummy)
                registry[target_path] = proxy
                visited_refs.add(target_path)
                try:
                    result = self._deeper(target,
                                          target_path,
                                          visited_refs=visited_refs,
                                          ref_resolver=ref_resolver,
                                          registry=registry,
                                          **context)
                except SchemaError as e:
                    registry[target_path] = Bad
                    raise SchemaError(
                        Error(path, self.messages['bad_reference']), *e.errors)

                except RecursiveReferenceError:
                    registry[target_path] = Bad
                    raise SchemaError(
                        Error(path, self.messages['recursive_reference']))

                else:
                    proxy.__wrapped__ = weakref.proxy(result)
                    registry[target_path] = result

                finally:
                    visited_refs.discard(target_path)

                return result

        except RefResolutionError:
            raise SchemaError(
                Error(path, self.messages['unresolvable_reference']))
예제 #2
0
    def _entry(self,
               value: ty.Any,
               path: Path,
               visited_refs: ty.Optional[VisitedRefs] = None,
               registry: ty.Optional[Registry] = None,
               **context: ty.Any) -> ty.Any:
        ref = self._get_ref(value)

        if ref is not None:
            return self._dive(ref,
                              path,
                              visited_refs=visited_refs,
                              registry=registry,
                              **context)

        else:
            assert registry is not None
            result = registry.get(path)

            if result is Bad:
                pass

            elif result is not None:
                return result

            proxy = ObjectProxy(Dummy)
            registry[path] = proxy
            try:
                result = self.subtype.convert(value,
                                              path,
                                              registry=registry,
                                              **context)
            except SchemaError:
                registry[path] = Bad
                raise

            else:
                proxy.__wrapped__ = weakref.proxy(result)
                registry[path] = result

            return result