def _get_origin_type(anno: Any, assert_is_type: bool = True) -> Any: # this part looks weird but it's working for 3.6-3.8 if anno is not None and anno.__module__ == "typing": if anno is Any: return object if hasattr(typing, "get_origin"): # pragma: no cover anno = typing.get_origin(anno) # type: ignore # 3.8 elif hasattr(anno, "__extra__"): # pragma: no cover anno = anno.__extra__ # < 3.7 elif hasattr(anno, "__origin__"): # pragma: no cover anno = anno.__origin__ # 3.7 if anno is None: # pragma: no cover anno = type(None) if assert_is_type: assert_or_throw( _is_native_type(anno), TypeError(f"Can't find python type for {anno}") ) return anno
def filter_by_type(self, T: Type[AuxObject]) -> List[AuxObject]: """Returns all `AuxObject`s with the given type. You can pass in Union types as well. """ if get_origin(T) == Union: T_raw = get_args(T) T = tuple(x for x in T_raw if x is not None) # T is a tuple of types def chk(x): try: return isinstance(x, T) except Exception: return False return [x for x in self._key_map.values() if chk(x)]
def _check(obj: Any, field: Field) -> None: name = field.name value = getattr(obj, name) actual = type(value) expected = get_type_hints(obj)[name] origin = get_origin(expected) if origin is list: pass raise NotImplementedError(f"""{expected=}, {is_generic_type(expected)} {is_union_type(expected)} {get_origin(expected)} """) if is_generic_type(expected): raise NotImplementedError(f"{expected=}") elif isinstance(expected, type): raise SingleDataClassTypeError(name, actual, expected) else: raise NotImplementedError(f"{expected=}")
def get_args(tp) -> Tuple[Any, ...]: """Get type arguments with all substitutions performed. For unions, basic simplifications used by Union constructor are performed. Examples:: get_args(Dict[str, int]) == (str, int) get_args(int) == () get_args(Union[int, Union[T, int], str][int]) == (int, str) get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) get_args(Callable[[], T][int]) == ([], int) """ if isinstance(tp, _GenericAlias): res = tp.__args__ if get_origin( tp) is collections.abc.Callable and res[0] is not Ellipsis: res = (list(res[:-1]), res[-1]) return res return ()
def from_nested_dict(cls, d, *, _nontype=type(None)): fields = dataclasses.fields(cls) # cache? params = {} for f in fields: if f.name in d: val = d[f.name] typ = f.type # optional: if hasattr(typ, "__origin__") and t.get_origin(typ) == t.Union: args = t.get_args(typ) if len(args) == 2 and _nontype in args: typ = args[1] if args[0] == _nontype else args[0] if hasattr(typ, "from_nested_dict"): val = typ.from_nested_dict(val) params[f.name] = val return cls(**params)
def _fromJsonBasic(type, field, value): if isinstance(type, SerializableType): inst = None if value is not None: inst = type.fromJson(value) return inst elif isinstance(type, SerializableEnumType): return type(type.fromJson(value)) elif hasattr(type, 'fromJson'): return type.fromJson(value) else: origin = get_origin(type) # cast the type, to allow for integer mappings # that can be round-tripped through a json representation if origin: return origin(value) else: return type(value)
def readstr(str_value: str, target): if isinstance(target, type) and issubclass(target, Enum): # noinspection PyUnresolvedReferences enum_value = target.__members__.get(str_value) \ or target.__members__.get(str_value.upper()) \ or target.__members__.get(str_value.lower()) if enum_value is not None: return enum_value if target in _READERS: return _READERS[target](str_value) origin = ty.get_origin(target) if origin is not None and origin in _READERS: return _READERS[origin](str_value, ty.get_args(target)) try: return target(str_value) except Exception as exc: raise ValueError( f'no way to convert into {target}: "{str_value}"') from exc
def recurse(t): if isinstance(t, str): raise _StringForwardRefError(forward_ref=t) elif isinstance(t, ForwardRef): if t.__forward_evaluated__: t = t.__forward_value__ else: raise _UnevaluatedForwardRefError(forward_ref=t) args = get_args(t) is_literal = Literal is not None and get_origin(t) is Literal if is_literal: yield Literal elif args: for arg in args: yield from recurse(arg) else: yield t
def __set_generic_types(cls: type, annotations: dict) -> None: for n, v in annotations.items(): if type(v) is TypeVar: annotations[n] = TypeInspect.__get_generic_type(cls) continue origin_v = get_origin(v) if origin_v is not None: if issubclass(origin_v, List) and type(v.__args__[0]) is TypeVar: generic_type = TypeInspect.__get_generic_type(cls) v.__args__ = (generic_type, ) # make List[~T] to List[generic_type] if issubclass(origin_v, Dict) and type(v.__args__[1]) is TypeVar: generic_type = TypeInspect.__get_generic_type(cls) v.__args__ = ( v.__args__[0], generic_type ) # make Dict[Any, ~T] to Dict[Any, genericType]
def get_type_representation(type_): type_origin = typing.get_origin(type_) if type_origin in (dict, list, tuple): type_ = type_origin elif type_origin is typing.Union: type_args = list(typing.get_args(type_)) try: type_args.remove(type(None)) except ValueError: pass if len(type_args) == 1: type_ = type_args[0] try: type_str = type_.__name__ except AttributeError: return '' return TYPE_NAME_MAP.get(type_str, type_str)
def get_json_type(type_: Type) -> Dict[str, Union[str, List, Dict]]: r""" Get the type for the JSON schema that corresponds to the given Python type. :param type\_: """ if type_ in json_type_lookup: return {"type": json_type_lookup[type_]} elif get_origin(type_) is Union: return {"type": [get_json_type(t)["type"] for t in type_.__args__]} elif check_type(type_, list, List): args = get_args(type_) if args: items = get_json_type(args[0]) if items is NotImplemented: return {"type": "array"} elif "type" in items: return {"type": "array", "items": items} elif "enum" in items: return {"type": "array", "items": items} else: return {"type": "array"} return {"type": "array"} elif check_type(type_, dict, Dict): return {"type": "object"} elif check_type(type_, Literal) or is_literal_type(type_): # type: ignore return {"enum": [x for x in get_literal_values(type_)]} elif isinstance(type_, EnumMeta): return {"enum": [x._value_ for x in type_]} elif type_ is bool: return {"type": ["boolean", "string"]} else: return NotImplemented
def isinstance_(x, test_type): """ native isinstance_ with the test for typing.Union overridden """ # TODO: TypeVar instances are treated as Any for the time being if test_type is Any or isinstance(test_type, TypeVar): return True if is_union(test_type): return any(isinstance_(x, t) for t in get_args(test_type)) if is_dict(test_type): if isinstance(x, dict): dict_args = get_args(test_type) return all( isinstance_(k, dict_args[0]) and isinstance_(v, dict_args[1]) for k, v in x.items()) if dict_args else True else: return False if is_list(test_type): if isinstance(x, list) or isinstance(x, UserList): list_type = get_args(test_type) return all(isinstance_(t, list_type[0]) for t in x) if list_type else True else: return False if is_tuple(test_type): if isinstance(x, tuple): tuple_args = get_args(test_type) return all( isinstance_(xv, tv) for xv, tv in zip(x, tuple_args)) if tuple_args else True else: return False if is_set(test_type): if isinstance(x, set): set_type = get_args(test_type) return all(isinstance_(e, set_type[0]) for e in x) if set_type else True else: return False return get_origin(test_type) is None and isinstance(x, test_type)
def __init_subclass__(cls, *args, **kwargs) -> None: """ Combines annotations & default values of this class with the one defined in sub-classes. Has similarities with the newly introduced typing.get_type_hints() function. """ super().__init_subclass__(*args, **kwargs) # type: ignore joined_ann = { k: v for k, v in cls._annots.items() if not (k[0] == '_' or 'ClassVar' in str(v)) } joined_defaults = cls._defaults.copy() joined_sks = cls._sks.copy() joined_aks = cls._aks.copy() for base in reversed(cls.mro()): if ann := getattr(base, '__annotations__', {}): defs = getattr(base, '__dict__', {}) for k, v in ann.items(): if k == '__slots__' or k[0] == '_' or 'ClassVar' in str(v): continue joined_ann[k] = v # update merged annotations joined_aks.add(k) # update set of known attribute names if k in defs: if type(defs[k]) is MemberDescriptorType: # is a slot if k in cls._slot_defaults: joined_defaults[k] = cls._slot_defaults[k] continue joined_defaults[k] = base.__dict__[k] # if None | with no default elif get_origin(v) in ( Union, UnionType ) and NoneType in get_args( v ) and k not in joined_defaults: # type: ignore[misc] joined_defaults[k] = None elif k in cls._slot_defaults: joined_defaults[k] = cls._slot_defaults[k] # allow subclasses to change default value without supplying a new annotation for k, v in getattr(base, '__dict__', {}).items(): if k in joined_ann and not k in ann: joined_defaults[k] = v
def _maybe_fill_missing( cls, ctx: commands.Context, parameters: Dict[str, inspect.Parameter], kwargs: Dict[str, Any], ): ignore_optional_for_conversion = ctx.command.ignore_optional_for_conversion for name, param in parameters.items(): if param.default is not param.empty: continue anno = param.annotation if (not ignore_optional_for_conversion and get_origin(anno) is Union and type(None) in get_args(anno)): kwargs[name] = None elif cls.__total__: raise commands.MissingRequiredArgument(param) else: kwargs[name] = cls.MISSING
def assert_instance_is_binarized(instance, dict_): # noqa: C901 for field_name in instance.get_field_names(): dict_value = dict_.get(ck(field_name), SENTINEL) if dict_value is SENTINEL: continue instance_value = getattr(instance, field_name) field_type = instance.get_field_type(field_name) if issubclass(field_type, SerializableMixin): assert_instance_is_binarized(instance_value, dict_value) else: origin = typing.get_origin(field_type) if origin and issubclass(origin, list): (item_type, ) = typing.get_args(field_type) for index, item in enumerate(dict_value): if issubclass(item_type, SerializableMixin): assert_instance_is_binarized(instance_value[index], item) elif issubclass(item_type, hexstr): assert isinstance( item, bytes), f'{item} of {field_name} is not binarized' if origin and issubclass(origin, dict): (item_key_type, item_value_type) = typing.get_args(field_type) for item_key, item_value in dict_value.items(): if issubclass(item_key_type, hexstr): assert isinstance( item_key, bytes ), f'{item_key} of {field_name} is not binarized' instance_item_key = hexstr.from_bytes( item_key) if isinstance(item_key, bytes) else item_key if issubclass(item_value_type, SerializableMixin): assert_instance_is_binarized( instance_value[instance_item_key], item_value) elif issubclass(item_value_type, hexstr): assert isinstance(item_value, bytes), ( f'{item_value} of {item_key} key of {field_name} is not binarized' ) elif issubclass(field_type, hexstr): assert isinstance( dict_value, bytes), f'{field_name} of {instance} is not binarized'
def extract_initable(t: type, inst=None) -> Optional[Callable[..., type]]: """Extract e.g `dict` from `Optional[dict]`. Returns None if non-extractable. >>> from typing import Optional, Dict, List >>> ei = extract_initable >>> ei(List[str]) is ei(List) is ei(list) is ei(Optional[List[str]]) is list True >>> ei(Dict[str,int]) is ei(Dict) is ei(dict) is ei(Optional[Dict[str,int]]) is dict True >>> class Foo: ... >>> ei(Foo) is Foo True """ if isinstance(t, ForwardRef): evaluated = resolve_forwardref(t, inst.__class__) return extract_initable(evaluated) # breakpoint() # return evaluated origin = typing.get_origin(t) if origin is None: # Any if inspect.getmodule(t) is typing: return None return t type_args = typing.get_args(t) if origin is not typing.Union: if issubclass(origin, Iterable) and type_args: if len(type_args) > 1: raise NotImplementedError( f"{t = }, {type_args = }, more than 1 type_args") return lambda *args: origin(map(type_args[0], *args)) return origin # origin is Union or Optional[foo] origins = [a for a in typing.get_args(t) if a != type(None)] if len(origins) == 1: origin = origins[0] return extract_initable(origin) return None
def GetUnionUnderlyingType(typeToCheck, matchingType=None): ''' This retrieves the underlying types behind a unioned type by appropriately passing in the required matching type in the matchingType input argument. If that is 'None' (not to be confused with NoneType), then it will retrieve the 'real' type behind the union, i.e not Nullable && not None ''' if (not(typing.get_origin(typeToCheck) == typing.Union)): return None for t in typing.get_args(typeToCheck): if (matchingType is None): if (t != type(None) and t != Nullable): return t else: if (t == matchingType): return t return None
def __handle_type_hint_args(cls_set: Set[type]) -> Set[type]: for cls in cls_set.copy(): cls_str = str(cls) if cls_str.startswith('typing.Optional') \ or cls_str.startswith('typing.Union'): cls_set.remove(cls) cls_set.update( __handle_type_hint_args(set(typing.get_args(cls)))) elif cls_str.startswith('typing.Any'): cls_set.remove(cls) cls_set.update({object, type(None)}) elif cls_str.startswith('typing.'): tmp = typing.get_origin(cls) if tmp is not None: cls_set.remove(cls) cls_set.update({tmp}) return cls_set
async def _transform_identifier( ctx: commands.Context, parameters: Dict[str, inspect.Parameter], kwargs: Dict[str, Any]) -> Optional[inspect.Parameter]: arg: str = await ctx.command.transform(ctx, _ident_param) try: parameter = parameters.pop(arg) except KeyError: if arg in kwargs: raise commands.BadArgument( f"Multiple values provided for argument `{arg}`") from None raise commands.BadArgument( f"No such setting by the name of `{arg}`") from None anno = parameter.annotation if get_origin(anno) is Union: # since a name was passed, suppress d.py's typing.Optional behavior parameter = parameter.replace(annotation=Union[tuple( filter(_not_nonetype, get_args(anno)))] # type: ignore ) return parameter
def _check_special_type(tp, name): """checking if the type is a container: ty.List, ty.Dict or ty.Union""" if sys.version_info.minor >= 8: return ty.get_origin(tp), ty.get_args(tp) else: if isinstance(tp, type): # simple type return None, () else: if tp._name == "List": return list, tp.__args__ elif tp._name == "Dict": return dict, tp.__args__ elif tp.__origin__ is ty.Union: return ty.Union, tp.__args__ else: warnings.warn( f"not type check for {name} field, type check not implemented for type {tp}" ) return None, ()
def best_match(val, types): # Best match : casting litterals is_litteral = tuple(typing.get_origin(t) is typing.Literal for t in types) casted = tuple(can_cast(val, t) for t in types) match = is_litteral and casted if any(match): index = match.index(max(match)) return index, types[index] # then instance match = tuple(matching_instance(val, t) for t in types) if any(match): index = match.index(max(match)) return index, types[index] # then can_cast match = casted if any(match): index = match.index(max(match)) return index, types[index] raise ValueError("No match for val {} and types {}".format(val, types))
def is_dict(type_value): """Check if a type is a dict type.""" if type_value is dict: return True if not is_typing_type(type_value): return False if not hasattr(type_value, "__origin__"): return False if sys.version_info < (3, 7): return type_value.__origin__ == typing.Dict if sys.version_info < (3, 8): return type_value.__origin__ == dict return typing.get_origin(type_value) == dict
def __detect_type_vars(cls, generic_cls: TAlias_generic_cls) \ -> list[TypeVar]: from typing import TypeVar, Generic, get_args, get_origin type_vars: list[TypeVar] = [] for orig_base in generic_cls.__orig_bases__: if get_origin(orig_base) is Generic: base_type_args = get_args(orig_base) if len(base_type_args) > 0: for type_arg in base_type_args: if isinstance(type_arg, TypeVar): type_vars.append(type_arg) else: type_vars += cls.__detect_type_vars(generic_cls=orig_base) return type_vars
def function_operator( function: t.Callable[..., t.Optional[Term]]) -> FunctionOperator: import inspect signature = inspect.signature(function) type_hints = t.get_type_hints(function) types: t.Dict[str, t.Type[Term]] = {} optionals: t.Set[str] = set() for parameter in signature.parameters.values(): typ = type_hints.get(parameter.name, Term) origin = t.get_origin(typ) args = t.get_args(typ) optional = False if origin is t.Union and len(args) == 2 and args[1] is type(None): typ = args[0] optional = True if not isinstance(typ, type) or not issubclass(typ, Term): raise InvalidParameterTypeError( f"invalid type annotation {typ} for parameter {parameter.name}" ) types[parameter.name] = typ if optional: optionals.add(parameter.name) def implementation(arguments: Arguments) -> t.Optional[Term]: try: bound_arguments = signature.bind(*arguments) except TypeError: return None else: for parameter in signature.parameters.values(): argument = bound_arguments.arguments.get(parameter.name, None) if argument is None: if parameter.name not in optionals: return None elif not isinstance(argument, types[parameter.name]): return None return function(*arguments) return FunctionOperator(implementation, name=getattr(function, "__name__", None))
def is_type_hint_instance_of(type_hint, mcs) -> bool: """Check if `type_hint` contains a `mcs` instance. This is an utilitarian function for `BaseResourceMeta`. ###### Parameters ###### * `type_hint`: type hint to check * `mcs`: metaclass to check For a given class `C`, instance of metaclass `MC`, all following expressions are evaluated to `True`: ```python is_type_hint_instance_of(C, MC) is_type_hint_instance_of(Iterable[C], MC) is_type_hint_instance_of(Optional[C], MC) is_type_hint_instance_of(Union[C, None], MC) is_type_hint_instance_of(Optional[Iterable[C]], MC) is_type_hint_instance_of(Union[Iterable[C], None], MC) ``` ###### Returned value ###### `True` in the shown cases, `Fasle` otherwise. """ if isinstance(type_hint, mcs): return True origin = typing.get_origin(type_hint) if origin is None: return False type_args = typing.get_args(type_hint) if origin is Union: # in case of Optional field, check if it is Union[BaseResourceMeta, None] if len(type_args) != 2: return False if type(None) not in type_args: return False return is_type_hint_instance_of(type_args[0], mcs) if origin is collections.abc.Iterable: # in case of an iterable, check if it is a BaseResource return is_type_hint_instance_of(type_args[0], mcs) return False
def convert( self, game: Game, type_: Union[NoneType, Type[GameObject]], obj: Optional[Any], ) -> Optional[GameObject]: """Convert `obj` to the given `type_`, in the context of the `game`.""" if (type_ is None) or (type_ is NoneType): if obj is None: return None raise TypeError(f"obj must be None, got {obj!r}") if isinstance(obj, type_): # also works if None, NoneType :) return obj _t_origin = get_origin(type_) _t_args = get_args(type_) if _t_origin is Union: # Union or Optional for arg in _t_args: try: return self.convert(game, arg, obj) except Exception: pass # We went through all args - couldn't convert. raise MafiaConverterError(obj, type_) elif _t_origin is not None: raise TypeError(f"{_t_origin!r} is not supported for conversion.") # Find the function - try direct match, or using first subclass that works func_map = self._map[type_] func = func_map.get(type(obj)) if func is not None: return func(game, obj) for t, f in func_map.items(): if isinstance(obj, t): try: return f(game, obj) except Exception: logger.exception(f"Couldn't convert using {f!r}, trying again.") raise MafiaConverterError(obj, type_)
def list_algorithm_params(resolver, abstract_pathname: str, **kwargs): types = list_types(resolver) sig = resolver.abstract_algorithms[abstract_pathname].__signature__ def resolve_parameter(p) -> OrderedDict: result: OrderedDict p_class = p if type(p) is type else p.__class__ if p_class is Combo: resolved = [resolve_parameter(psub) for psub in p.types] combo_type = " or ".join(r["type"] for r in resolved) choices = [c for r in resolved for c in r["choices"]] if p.optional: combo_type += " or None" choices.append("NoneType") result = OrderedDict([("type", combo_type), ("choices", choices)]) elif issubclass(p_class, AbstractType): choices = list(types[p_class.__name__]["children"].keys()) result = OrderedDict([("type", p_class.__name__), ("choices", choices)]) elif typing.get_origin(p) == collections.abc.Callable: result = OrderedDict([("type", p._name), ("choices", [p._name])]) elif p is typing.Any: result = OrderedDict([("type", "Any"), ("choices", ["Any"])]) else: result = OrderedDict([("type", p_class.__name__), ("choices", [p_class.__name__])]) return result params = OrderedDict() for pname, p in sig.parameters.items(): params[pname] = resolve_parameter(p.annotation) returns = [] if typing.get_origin(sig.return_annotation) is tuple: for ret in typing.get_args(sig.return_annotation): returns.append(resolve_parameter(ret)) else: returns.append(resolve_parameter(sig.return_annotation)) return { "parameters": params, "returns": returns, }
def get_field_type(field_type, metadata): simple_types = { int: "int", str: "str", float: "float", bool: "bool", Path: "path" } complex_types = { list: "list", dict: "dict", Union: "union", tuple: "tuple", } special_cases = {Coordinate: "coordinate"} if field_type in simple_types: return handle_simple_types(field_type, metadata) elif get_origin(field_type) in complex_types: return handle_complex_types(field_type, metadata) elif field_type in special_cases: return handle_special_cases(field_type, metadata) elif issubclass(field_type, Enum): return handle_enum(field_type, metadata) else: try: configurable = getattr(dacapo.configurables, field_type.__name__) fields = parse_fields(configurable) return { "type": "configurable", "fields": fields, "help_text": metadata.get("help_text"), } except AttributeError: pass raise ValueError(f"Unsupported type: {field_type}, " f"origin: {get_origin(field_type)}, " f"args: {get_args(field_type)}")
def do_decode(cls, obj: Any, obj_type: Type[DecodableType]) -> Any: """Decodes json into the specified type Args: obj: the json object to decode obj_type: a class object which is the type we're decoding into. """ type_origin = get_origin(obj_type) type_args = get_args(obj_type) if inspect.isclass(obj_type) and issubclass(obj_type, ConjureBeanType): return cls.decode_conjure_bean_type(obj, obj_type) elif inspect.isclass(obj_type) and issubclass(obj_type, ConjureUnionType): return cls.decode_conjure_union_type(obj, obj_type) elif inspect.isclass(obj_type) and issubclass(obj_type, ConjureEnumType): return cls.decode_conjure_enum_type(obj, obj_type) elif isinstance(obj_type, DictType): return cls.decode_dict(obj, obj_type.key_type, obj_type.value_type) elif isinstance(obj_type, ListType): return cls.decode_list(obj, obj_type.item_type) elif isinstance(obj_type, OptionalType): return cls.decode_optional(obj, obj_type.item_type) elif type_origin is OptionalTypeWrapper: return cls.decode_optional(obj, type_args[0]) elif type_origin is dict: (key_type, value_type) = type_args return cls.decode_dict(obj, key_type, value_type) elif type_origin is list: return cls.decode_list(obj, type_args[0]) return cls.decode_primitive(obj, obj_type)
def check_type(name, value, annotation): if annotation is inspect._empty or annotation is Any: return value if type(annotation) is type: if type(value) is annotation: return value else: raise InputTypeError(name).from_types(type(value), annotation) origin = typing.get_origin(annotation) args = typing.get_args(annotation) if type(annotation) is TypeVar: return check_typevar(name, value, annotation, args) if origin is CallableType: return check_callable(name, value, args) if origin is Union: return check_union(name, value, args) if origin is list: value = check_type(name, value, list) return check_list(name, value, args) if origin is tuple: value = check_type(name, value, tuple) return check_tuple(name, value, args) if origin is dict: value = check_type(name, value, dict) return check_dict(name, value, args) if origin is Literal: return check_literal(name, value, args) if issubclass(origin, IsopyType): return origin.check_type(name, value, args) print('not caught', name, value, annotation, origin, args) return value