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
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)
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)
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