예제 #1
0
    def iterator(self, type: Type, values: bool = False) -> "FieldIteratorT":
        """Get an iterator function for a given type, if possible."""

        if ismappingtype(type):
            iter = _valuescaller if values else _itemscaller
            return iter

        if isiterabletype(type):
            return _iter

        fields = self.get_fields(type, as_source=True) or {}

        if fields:
            func_name = get_defname("iterator", (type, values))
            oname = "o"
            ctx: dict = {}
            with Block(ctx) as main:
                with main.f(func_name, Block.p(oname)) as func:
                    if values:
                        for f in fields:
                            func.l(f"{Keyword.YLD} {oname}.{f}")
                    else:
                        for f in fields:
                            func.l(f"{Keyword.YLD} {f!r}, {oname}.{f}")

            return main.compile(name=func_name, ns=ctx)

        raise TranslatorTypeError(
            f"Cannot get iterator for type {type!r}, unable to determine fields."
        ) from None
예제 #2
0
 def _compile_iterable_translator(self, source: Type, target: Type) -> TranslatorT:
     func_name = self._get_name(source, target)
     target_name = get_name(target)
     oname = "o"
     ismapping = ismappingtype(target)
     iterator = self.iterator(source, not ismapping)
     ctx = {"iterator": iterator, target_name: target}
     with Block(ctx) as main:
         with main.f(func_name, Block.p(oname)) as func:
             retval = f"iterator({oname})"
             if not isiteratortype(target):
                 retval = f"{target_name}({retval})"
             func.l(f"{Keyword.RET} {retval}")
     return main.compile(name=func_name)
예제 #3
0
    def iterator(
        self,
        type: Type,
        values: bool = False,
        relaxed: bool = False,
        exclude: Tuple[str, ...] = (),
    ) -> IteratorT:
        """Get an iterator function for a given type, if possible."""
        mapping, iterable, builtin, namedtuple, typicklass = (
            ismappingtype(type),
            isiterabletype(type),
            isbuiltinsubtype(type),
            isnamedtuple(type),
            istypicklass(type),
        )
        if mapping:
            return _valuescaller if values else _itemscaller

        if (iterable, namedtuple, typicklass) == (True, False, False):
            return iter if values else enumerate

        if (builtin, iterable) == (True, False):
            raise TranslatorTypeError(
                f"Cannot get iterator for type {type.__name__!r}."
            ) from None

        fields = self.get_fields(type, as_source=True, exclude=exclude) or {}

        if not fields and not relaxed:
            raise TranslatorTypeError(
                f"Cannot get iterator for type {type.__name__!r}, "
                f"unable to determine fields."
            ) from None

        func_name = get_defname("iterator", (type, values))
        oname = "o"
        ctx: dict = {}
        with Block(ctx) as main:
            with main.f(func_name, Block.p(oname)) as func:
                if fields:
                    if values:
                        for f in fields:
                            func.l(f"{Keyword.YLD} {oname}.{f}")
                    else:
                        for f in fields:
                            func.l(f"{Keyword.YLD} {f!r}, {oname}.{f}")
                else:
                    func.l(f"{Keyword.YLD}")

        return main.compile(name=func_name, ns=ctx)
예제 #4
0
    def _compile_translator(
        self, source: Type, target: Type, exclude: Tuple[str, ...] = ()
    ) -> TranslatorT:
        if isliteral(target):
            raise TranslatorTypeError(
                f"Cannot translate to literal type: {target!r}. "
            ) from None
        if isliteral(source):
            raise TranslatorTypeError(
                f"Cannot translate from literal type: {source!r}. "
            ) from None
        # Get the target fields for translation.
        target_fields = self.get_fields(target)
        if target_fields is None:
            if isiterabletype(target):
                return self._compile_iterable_translator(source, target)
            raise TranslatorTypeError(
                f"Cannot translate to type {target!r}. "
                f"Unable to determine target fields."
            ) from None

        # Ensure that the target fields are a subset of the source fields.
        # We treat the target fields as the parameters for the target,
        # so this must be true.
        fields = self.get_fields(source, as_source=True, exclude=exclude) or {}
        fields_to_pass = {x: fields[x] for x in fields.keys() & target_fields.keys()}
        required = self.required_fields(target_fields)
        if not required.issubset(fields_to_pass.keys()):
            diff = (*(required - fields.keys()),)
            raise TranslatorValueError(
                f"{source!r} can't be translated to {target!r}. "
                f"Source is missing required fields: {diff}."
            ) from None
        protocols = self.resolver.protocols(target)

        # Build the translator.
        anno_name = get_unique_name(source)
        target_name = get_unique_name(target)
        func_name = self._get_name(source, target)
        oname = "o"
        ctx: Dict[str, Any] = {target_name: target, anno_name: source}
        with Block(ctx) as main:
            with main.f(func_name, Block.p(oname)) as func:
                args = ", ".join(
                    self._iter_field_assigns(fields_to_pass, oname, protocols, ctx)
                )
                func.l(f"{Keyword.RET} {target_name}({args})")
        trans = main.compile(name=func_name, ns=ctx)
        return trans