def simplify_generics(obj1, obj2, two_element_transformers: List[Callable]): if not typing_inspect.is_generic_type( obj1) or not typing_inspect.is_generic_type(obj2): return NOT_SIMPLIFIED if typing_inspect.get_origin(obj1) != typing_inspect.get_origin(obj2): return NOT_SIMPLIFIED # print() # print('trying to simplify', obj1, obj2, sep='\n') transformed = [] for arg1, arg2 in zip(obj1.__args__, obj2.__args__): # print('arg1, arg2: ', arg1, arg2) for transformer in [collapse_unions, *two_element_transformers]: transformed_obj = transformer(arg1, arg2) if transformed_obj is not NOT_SIMPLIFIED: transformed.append(transformed_obj) break else: return NOT_SIMPLIFIED result = typing_inspect.get_origin(obj1)[tuple(transformed)] # print('result', result) return result
def _validate_return_type(self, arg_type: Type, *, strict: bool = True) -> None: """Validate the return type""" # Note: we cannot call issubclass on a generic type! arg = "return type" if typing_inspect.is_generic_type(arg_type) and issubclass( typing_inspect.get_origin(arg_type), ReturnValue): self._validate_type_arg(arg, typing_inspect.get_args(arg_type, evaluate=True)[0], strict=strict, allow_none_type=True) elif not typing_inspect.is_generic_type(arg_type) and isinstance( arg_type, type) and issubclass(arg_type, ReturnValue): raise InvalidMethodDefinition( "ReturnValue should have a type specified.") else: self._validate_type_arg(arg, arg_type, allow_none_type=True, strict=strict)
def _validate_union_return(self, arg_type: Type, value: Any) -> None: """Validate a return with a union type :see: protocol.common.MethodProperties._validate_function_types """ matching_type = None for t in typing_inspect.get_args(arg_type, evaluate=True): instanceof_type = t if typing_inspect.is_generic_type(t): instanceof_type = typing_inspect.get_origin(t) if isinstance(value, instanceof_type): if matching_type is not None: raise exceptions.ServerError( f"Return type is defined as a union {arg_type} for which multiple " f"types match the provided value {value}" ) matching_type = t if matching_type is None: raise exceptions.BadRequest( f"Invalid return value, no matching type found in union {arg_type} for value type {type(value)}" ) if typing_inspect.is_generic_type(matching_type): self._validate_generic_return(arg_type, matching_type)
def do_explode(self, kind): if kind in basic_types or type(kind) is typing.TypeVar: return False if typing_inspect.is_generic_type(kind) and issubclass(typing_inspect.get_origin(kind), Sequence): return False if typing_inspect.is_generic_type(kind) and issubclass(typing_inspect.get_origin(kind), Mapping): return False self.clear() self.extend(Args(self.schema, kind)) return True
def remove_empty_container(obj1, obj2): if not typing_inspect.is_generic_type( obj1) or not typing_inspect.is_generic_type(obj2): return NOT_SIMPLIFIED if obj1._gorg != obj2._gorg: return NOT_SIMPLIFIED if _is_empty(obj1): return obj2 if _is_empty(obj2): return obj1 return NOT_SIMPLIFIED
def is_return_value_type(arg_type: Type) -> bool: if typing_inspect.is_generic_type(arg_type): origin = typing_inspect.get_origin(arg_type) assert origin is not None # Make mypy happy return types.issubclass(origin, ReturnValue) else: return False
def type_from_annotation(annotation): if annotation == inspect._empty: return None elif annotation == t.Any: return AnyType() elif ti.is_generic_type(annotation): g_origin = ti.get_origin(annotation) g_args = ti.get_args(annotation) if g_origin in [list]: # Better way? base_type = type_from_annotation(g_args[0]) return ListType(type=base_type) elif g_origin in [dict]: # Better way? key_type = type_from_annotation(g_args[0]) value_type = type_from_annotation(g_args[1]) return MapType(key_type=key_type, value_type=value_type) elif inspect.isclass(annotation): if issubclass(annotation, BaseResource): return ResourceType(type=annotation) else: return ScalarType(type=annotation) else: raise Exception(f'Unhandled annotation {annotation}')
def _generate_field_schema(field: Field, context: str, schemas: Dict[str, Schema]) -> Tuple[bool, Schema]: is_optional, annotation = extract_optional_annotation(field.annotation) if is_schema(annotation): field_schema_name = _generate_schema(context, annotation, schemas) field_schema = Schema(all_of=[_make_schema_ref(field_schema_name)]) elif is_generic_type(annotation): origin = get_origin(annotation) if origin in (list, List): arguments = get_args(annotation) if not arguments or arguments == [Any] or is_typevar(arguments[0]): field_schema = _generate_primitive_schema(list) else: item_schema_name = _generate_schema(context, arguments[0], schemas) field_schema = Schema("array", items=_make_schema_ref(item_schema_name)) elif origin in (dict, Dict): # TODO: Improve support for dicts. field_schema = _generate_primitive_schema(dict) else: field_schema = _generate_primitive_schema(annotation) if field_schema is not None: field_schema.description = field.description for option, value in field.validator_options.items(): if option in Schema._FIELDS: setattr(field_schema, option, value) return is_optional, field_schema
def check_args(cls: Type, generic_base_class: Type, typevar: TypeVar) -> int: """ Performs argument-validation for get_argument_to_typevar. :param cls: The sub-class specifying the argument. :param generic_base_class: The generic base-class specifying the type variable. :param typevar: The type variable to get the argument for. :return: The index of the typevar in the base class' parameters. """ # Make sure the class derives from the base-class if not issubclass(cls, generic_base_class): raise ValueError( f"{cls.__name__} does not derive from {generic_base_class.__name__}" ) # Make sure the base class is generic if not typing_inspect.is_generic_type(generic_base_class): raise TypeError(f"{generic_base_class.__name__} is not a generic type") # Get the type parameters to the generic base class parameters = typing_inspect.get_parameters(generic_base_class) # Make sure the type variable is a parameter to the base class if typevar not in parameters: raise ValueError( f"{typevar} is not a generic parameter of {generic_base_class.__name__}" ) return parameters.index(typevar)
def _rewrite(self, typ: type): if isinstance(typ, _Any): return typ arg_classes = getattr(typ, '__args__', []) if not arg_classes: return typ if typing_inspect.is_generic_type(typ) or typing_inspect.is_tuple_type( typ): gorg = typing_inspect.get_origin(typ) processed_args = [] for arg_class in arg_classes: processed = self._rewrite(arg_class) if processed is NOT_SIMPLIFIED: processed = arg_class processed_args.append(processed) return gorg[tuple(processed_args)] processed_args = [] for arg_class in arg_classes: rewritten = self._rewrite(arg_class) if rewritten is NOT_SIMPLIFIED: processed_args.append(arg_class) continue processed_args.append(rewritten) new_union = make_union(processed_args) new_union = self.union_rewriter.rewrite_Union(new_union) return new_union
def extract_generic(tp: Type[T]) -> Tuple[bool, Type[T], Tuple[Type, ...]]: """ Helper function that checks if the given type is generic, and if it is, expands it. Args: tp: `Type[T]` - potentially generic type. Returns: Returns a tuple of 3 values. - `bool`: **True** if the given type is `Generic`; **False** otherwise. - `Type[R]`: The class *T*, if *T* is not optional; and *R* if *T* is `Optional[R]`. - `Tuple[Type, ...]`: The tuple of class parameters used for *T*'s creation; empty tuple if it is not generic. Examples: ```python extract_generic(dict) # => (False, dict, ()) extract_generic(Dict[A, B]) # => (True, Dict, (A, B)) extract_generic(Optional[int]) # => (True, Union, (int, None)) extract_generic(MyClass[str]) # => (True, MyClass, (str)) extract_generic(Union[MyClass[str], None]) # => (True, Union, (MyClass[str], None)) ``` """ if (isinstance(tp, GenericProxy)): # noinspection PyTypeChecker return True, tp.base, tp.args if (is_generic_type(tp)): base = get_origin(tp) return True, base, get_args(tp, evaluate=True) else: return False, tp, tuple()
def _generate_field_schema(field_name: str, field: Field, schemas: Dict[str, Schema]) -> Tuple[bool, Schema]: is_optional, annotation = extract_optional_annotation(field.annotation) if is_schema(annotation): field_schema_name = _generate_schema(annotation, schemas) field_schema = Schema(ref=_make_ref_path(field_schema_name)) elif is_generic_type(annotation): origin = get_origin(annotation) if origin in _LIST_TYPES: arguments = get_args(annotation) if arguments and is_schema(arguments[0]): item_schema_name = _generate_schema(arguments[0], schemas) field_schema = Schema("array", items=_make_schema_ref(item_schema_name)) else: field_schema = _generate_primitive_schema(annotation) elif origin in _DICT_TYPES: # TODO: Add support for additionalFields. field_schema = _generate_primitive_schema(dict) else: # pragma: no cover raise ValueError( f"Unsupported type {origin} for field {field.name!r}.") elif is_union_type(annotation): sub_schemas = [] for arg in get_args(annotation): _, sub_schema = _generate_field_schema("", Field(annotation=arg), schemas) sub_schemas.append(dump_schema(sub_schema, sparse=True)) field_schema = Schema(any_of=sub_schemas) else: field_schema = _generate_primitive_schema(annotation) if field_schema is not None: field_schema.description = field.description if field.request_name != field.response_name: if field_name == field.request_name: field_schema.write_only = True else: field_schema.read_only = True elif field.response_only: field_schema.read_only = True elif field.request_only: field_schema.write_only = True for option, value in field.validator_options.items(): if option in Schema._FIELDS: setattr(field_schema, option, value) return is_optional, field_schema
def _get_iterable_of(t: Type) -> Optional[Type]: if not typing_inspect.is_generic_type(t): return None origin = typing_inspect.get_origin(t) args = typing_inspect.get_args(t, evaluate=True) if origin in (list, List, Iterable, Iterator): return args[0] return None
def inspect_type(t) -> InspectedType: """Returns basic information on a type as an InspectedType""" args = typing_inspect.get_args(t) if typing_inspect.is_generic_type(t): origin = typing_inspect.get_origin(t) else: origin = t return InspectedType(type=t, origin=origin, args=args)
def _check_annotation(f_type, f_fullname, f_default): if typing_inspect.is_tuple_type(f_type): if f_default is not None: raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'default is defined for tuple type') f_default = tuple elif typing_inspect.is_union_type(f_type): for t in typing_inspect.get_args(f_type, evaluate=True): _check_annotation(t, f_fullname, f_default) elif typing_inspect.is_generic_type(f_type): if f_default is not None: raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'default is defined for container type ' f'{f_type!r}') ot = typing_inspect.get_origin(f_type) if ot is None: raise RuntimeError( f'cannot find origin of a generic type {f_type}') if ot in (list, List, collections.abc.Sequence): f_default = list elif ot in (set, Set): f_default = set elif ot in (frozenset, FrozenSet): f_default = frozenset elif ot in (dict, Dict): f_default = dict else: raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'{f_type!r} is not supported') elif f_type is not None: if f_type is Any: f_type = object if not isinstance(f_type, type): raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'{f_type!r} is not a type') if typeutils.is_container_type(f_type): if f_default is not None: raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'default is defined for container type ' f'{f_type!r}') # Make sure that we can actually construct an empty # version of this type before we decide it is the default. try: f_type() except TypeError: pass else: f_default = f_type return f_default
def _generic_to_tuple( type_: _tp.Type[_tp.Any] ) -> _tp.Union[_tp.Type[_tp.Any], _tp.Tuple[_tp.Type[_tp.Any], ...]]: if _typing_inspect.is_generic_type(type_): class_ = _typing_inspect.get_origin(type_) types = _typing_inspect.get_args(type_) return (class_, *types) return type_
def _type_from_value(value, ctx): if isinstance(value, KnownValue): return _type_from_runtime(value.val, ctx) elif isinstance(value, _SubscriptedValue): if not isinstance(value.root, KnownValue): ctx.show_error("Cannot resolve subscripted annotation: %s" % (value.root, )) return UNRESOLVED_VALUE root = value.root.val if root is typing.Union: return unite_values( *[_type_from_value(elt, ctx) for elt in value.members]) elif is_typing_name(root, "Literal"): if all(isinstance(elt, KnownValue) for elt in value.members): return unite_values(value.members) else: ctx.show_error( "Arguments to Literal[] must be literals, not %s" % (value.members, )) return UNRESOLVED_VALUE elif root is typing.Optional: if len(value.members) != 1: ctx.show_error("Optional[] takes only one argument") return UNRESOLVED_VALUE return unite_values(KnownValue(None), _type_from_value(value.members[0], ctx)) elif root is typing.Type: if len(value.members) != 1: ctx.show_error("Type[] takes only one argument") return UNRESOLVED_VALUE argument = _type_from_value(value.members[0], ctx) if isinstance(argument, TypedValue) and isinstance( argument.typ, type): return SubclassValue(argument.typ) return TypedValue(type) elif typing_inspect.is_generic_type(root): origin = typing_inspect.get_origin(root) if getattr(origin, "__extra__", None) is not None: origin = origin.__extra__ return GenericValue( origin, [_type_from_value(elt, ctx) for elt in value.members]) elif isinstance(root, type): return GenericValue( root, [_type_from_value(elt, ctx) for elt in value.members]) else: # In Python 3.9, generics are implemented differently and typing.get_origin # can help. origin = get_origin(root) if origin is not None: return GenericValue( origin, [_type_from_value(elt, ctx) for elt in value.members]) ctx.show_error("Unrecognized subscripted annotation: %s" % (root, )) return UNRESOLVED_VALUE else: return UNRESOLVED_VALUE
def _maybe_node_for_dict( typ: Type[iface.IType], overrides: OverridesT, memo: MemoType, forward_refs: ForwardRefs, supported_type=frozenset({ dict, collections.abc.Mapping, pyt.PMap, }), supported_origin=frozenset({ Dict, dict, collections.abc.Mapping, pyt.PMap, }) ) -> Tuple[Optional[schema.nodes.SchemaNode], MemoType, ForwardRefs]: """ This is mainly for cases when a user has manually specified that a field should be a dictionary, rather than a strict structure, possibly due to dynamic nature of keys (for instance, python logging settings that have an infinite set of possible attributes). """ rv = None # This is a hack for Python 3.9 if insp.is_generic_type(typ): generic_bases = [get_origin_39(x) for x in insp.get_generic_bases(typ)] else: generic_bases = [] typ = dict if is_39_deprecated_dict(typ) else typ if typ in supported_type or get_origin_39( typ) in supported_origin or are_generic_bases_match( generic_bases, supported_origin): schema_node_type = schema.nodes.PMapSchema if is_pmap( typ) else schema.nodes.SchemaNode if generic_bases: # python 3.9 args key_type, value_type = typ.__args__ else: try: key_type, value_type = insp.get_args(typ) except ValueError: # Mapping doesn't provide key/value types key_type, value_type = Any, Any key_node, memo, forward_refs = decide_node_type( key_type, overrides, memo, forward_refs) value_node, memo, forward_refs = decide_node_type( value_type, overrides, memo, forward_refs) mapping_type = schema.types.TypedMapping(key_node=key_node, value_node=value_node) rv = schema_node_type(mapping_type) return rv, memo, forward_refs
def is_type(type_or_hint) -> bool: """ returns whether the type or hint is a Type typehint """ if not is_generic_type(type_or_hint): return False if NEW_TYPING: return get_origin(type_or_hint) is type else: return getattr(type_or_hint, "__extra__", None) is type
def __call__(self, tp): if inspect.isclass(tp): return self.iter_mro(tp) if ti.is_optional_type(tp): return self.iter_optional(tp) if ti.is_tuple_type(tp): return self.iter_generic(tp) if ti.is_union_type(tp): return self.iter_generic(tp) if ti.is_generic_type(tp): return self.iter_generic(tp)
def __set_name__(self, cls: 'ObjectMeta', name: str) -> None: super().__set_name__(cls, name) if not self.pipe: ann = get_type_hints(cls).get(name, None) if (not is_generic_type(ann) and get_origin(ann) is not type(self) and len(get_args(ann)) != 1): raise TypeError('no type or conversions ' 'specified for member {!r}'.format(name)) self.pipe = (jsontype(get_args(ann)[0]), ) self.json_to = _compose(*(p[0] for p in self.pipe)) self.for_json = _compose(*(p[1] for p in reversed(self.pipe)))
def _repr(val: t.Any) -> str: assert val is not None if types.is_none_type(val): return 'NoneType' elif ti.is_literal_type(val): return str(val) elif ti.is_new_type(val): nested_type = val.__supertype__ return f'{_qualified_name(val)}[{get_repr(nested_type)}]' elif ti.is_typevar(val): tv_constraints = ti.get_constraints(val) tv_bound = ti.get_bound(val) if tv_constraints: constraints_repr = (get_repr(tt) for tt in tv_constraints) return f'typing.TypeVar(?, {", ".join(constraints_repr)})' elif tv_bound: return get_repr(tv_bound) else: return 'typing.Any' elif ti.is_optional_type(val): optional_args = ti.get_args(val, True)[:-1] nested_union = len(optional_args) > 1 optional_reprs = (get_repr(tt) for tt in optional_args) if nested_union: return f'typing.Optional[typing.Union[{", ".join(optional_reprs)}]]' else: return f'typing.Optional[{", ".join(optional_reprs)}]' elif ti.is_union_type(val): union_reprs = (get_repr(tt) for tt in ti.get_args(val, True)) return f'typing.Union[{", ".join(union_reprs)}]' elif ti.is_generic_type(val): attr_name = val._name generic_reprs = (get_repr(tt) for tt in ti.get_args(val, evaluate=True)) return f'typing.{attr_name}[{", ".join(generic_reprs)}]' else: val_name = _qualified_name(val) maybe_td_entries = getattr(val, '__annotations__', {}).copy() if maybe_td_entries: # we are dealing with typed dict # that's quite lovely td_keys = sorted(maybe_td_entries.keys()) internal_members_repr = ', '.join( '{key}: {type}'.format(key=k, type=get_repr(maybe_td_entries.get(k))) for k in td_keys ) return f'{val_name}{{{internal_members_repr}}}' elif 'TypedDict' == getattr(val, '__name__', ''): return 'typing_extensions.TypedDict' else: return val_name
def decode_generic_dict(decoder, typ, json_value): if not (inspect.is_generic_type(typ) and inspect.get_origin(typ) == dict): return Unsupported check_type(dict, json_value) key_type, value_type = inspect.get_args(typ) if key_type != str: raise JsonError( f'Dict key type {key_type} is not supported for JSON deserialization - key should be str' ) return { key: decoder.decode(value_type, value) for (key, value) in json_value.items() }
def _init_parametric_user(cls) -> None: """Initialize an indirect descendant of ParametricType.""" # For ParametricType grandchildren we have to deal with possible # TypeVar remapping and generally check for type sanity. ob = getattr(cls, '__orig_bases__', ()) for b in ob: if (isinstance(b, type) and issubclass(b, ParametricType) and b is not ParametricType): raise TypeError( f'{cls.__name__}: missing one or more type arguments for' f' base {b.__name__!r}') if not typing_inspect.is_generic_type(b): continue org = typing_inspect.get_origin(b) if not isinstance(org, type): continue if not issubclass(org, ParametricType): continue base_params = getattr(org, '__parameters__', ()) args = typing_inspect.get_args(b) expected = len(base_params) if len(args) != expected: raise TypeError( f'{b.__name__} expects {expected} type arguments' f' got {len(args)}') base_map = dict(cls._type_param_map) subclass_map = {} for i, arg in enumerate(args): if not typing_inspect.is_typevar(arg): raise TypeError(f'{b.__name__} expects all arguments to be' f' TypeVars') base_typevar = base_params[i] attr = base_map.get(base_typevar) if attr is not None: subclass_map[arg] = attr if len(subclass_map) != len(base_map): raise TypeError( f'{cls.__name__}: missing one or more type arguments for' f' base {org.__name__!r}') cls._type_param_map = subclass_map
def validate(self, value: Optional[Any]) -> _T: """Validate and possibly transform the given value. Raises: FieldValidationError: When the value is not valid. """ is_optional, annotation = extract_optional_annotation(self.annotation) # Distinguishing between missing values and null values is # important. Optional types can have None as a value whereas # types with a default cannot. Additionally, it's possible to # have an optional type without a default value. if value is Missing: if self.default is not Missing: return self.default elif self.default_factory: return self.default_factory() elif is_optional: return None raise FieldValidationError("this field is required") if value is None: if not is_optional: raise FieldValidationError("this field cannot be null") return value if annotation not in (Any,) and \ not is_forward_ref(annotation) and \ not is_generic_type(annotation) and \ not is_union_type(annotation) and \ not is_typevar(annotation) and \ not is_schema(annotation) and \ not isinstance(value, annotation): if not self.allow_coerce: raise FieldValidationError( f"unexpected type {type(value).__name__}") try: value = annotation(value) except Exception: raise FieldValidationError( f"value could not be coerced to {annotation.__name__}") if self.validator: return self.validator.validate(self, value, **self.validator_options) return value
def get_all_subclasses(typ, recursive: bool = True, _memo=None) -> Sequence[Type[Any]]: """ Returns all subclasses, and supports generic types. It is recursive by default See discussion at https://github.com/Stewori/pytypes/issues/31 :param typ: :param recursive: a boolean indicating whether recursion is needed :param _memo: internal variable used in recursion to avoid exploring subclasses that were already explored :return: """ _memo = _memo or set() # if we have collected the subclasses for this already, return if typ in _memo: return [] # else remember that we have collected them, and collect them _memo.add(typ) if is_generic_type(typ): # We now use get_origin() to also find all the concrete subclasses in case the desired type is a generic sub_list = get_origin(typ).__subclasses__() else: sub_list = typ.__subclasses__() # recurse result = [] for t in sub_list: # only keep the origins in the list to = get_origin(t) or t try: if to is not typ and to not in result and is_subtype( to, typ, bound_typevars={}): result.append(to) except: # catching an error with is_subtype(Dict, Dict[str, int], bound_typevars={}) pass # recurse if recursive: for typpp in sub_list: for t in get_all_subclasses(typpp, recursive=True, _memo=_memo): # unfortunately we have to check 't not in sub_list' because with generics strange things happen # also is_subtype returns false when the parent is a generic if t not in sub_list and is_subtype(t, typ, bound_typevars={}): result.append(t) return result
def _check_annotation(f_type, f_fullname, f_default): if typing_inspect.is_tuple_type(f_type): if f_default is not None: raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'default is defined for tuple type') f_default = tuple elif typing_inspect.is_union_type(f_type): for t in typing_inspect.get_args(f_type, evaluate=True): _check_annotation(t, f_fullname, f_default) elif typing_inspect.is_generic_type(f_type): if f_default is not None: raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'default is defined for container type ' f'{f_type!r}') ot = typing_inspect.get_origin(f_type) if ot is None: raise RuntimeError( f'cannot find origin of a generic type {f_type}') if ot in (list, typing.List): f_default = list elif ot in (set, typing.Set): f_default = set elif ot in (frozenset, typing.FrozenSet): f_default = frozenset elif ot in (dict, typing.Dict): f_default = dict else: raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'{f_type!r} is not supported') elif f_type is not None: if not isinstance(f_type, type): raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'{f_type!r} is not a type') if typeutils.is_container_type(f_type): if f_default is not None: raise RuntimeError(f'invalid type annotation on {f_fullname}: ' f'default is defined for container type ' f'{f_type!r}') f_default = f_type return f_default
def _build_return_value_wrapper(self, url_method_properties: MethodProperties) -> Optional[Dict[str, MediaType]]: return_type = inspect.signature(url_method_properties.function).return_annotation if return_type is None or return_type == inspect.Signature.empty: return None return_properties: Optional[Dict[str, Schema]] = None if return_type == ReturnValue or is_generic_type(return_type) and get_origin(return_type) == ReturnValue: # Dealing with the special case of ReturnValue[...] links_type = self.type_converter.get_openapi_type(Dict[str, str]) links_type.title = "Links" links_type.nullable = True warnings_type = self.type_converter.get_openapi_type(List[str]) warnings_type.title = "Warnings" return_properties = { "links": links_type, "metadata": Schema( title="Metadata", nullable=True, type="object", properties={ "warnings": warnings_type, }, ), } type_args = get_args(return_type, evaluate=True) if not type_args or len(type_args) != 1: raise RuntimeError( "ReturnValue definition should take one type Argument, e.g. ReturnValue[None]. " f"Got this instead: {type_args}" ) if not url_method_properties.envelope: raise RuntimeError("Methods returning a ReturnValue object should always have an envelope") if type_args[0] != NoneType: return_properties[url_method_properties.envelope_key] = self.type_converter.get_openapi_type(type_args[0]) else: openapi_return_type = self.type_converter.get_openapi_type(return_type) if url_method_properties.envelope: return_properties = {url_method_properties.envelope_key: openapi_return_type} return {"application/json": MediaType(schema=Schema(type="object", properties=return_properties))}
def is_list_type(tp) -> bool: """ Test if the type is a generic list type, including subclasses excluding non-generic classes. Examples:: is_list_type(int) == False is_list_type(list) == False is_list_type(List) == True is_list_type(List[str, int]) == True class MyClass(List[str]): ... is_list_type(MyClass) == True """ return is_generic_type(tp) and issubclass(get_origin(tp) or tp, List)
def to_json_value(self): dct = {} dct['_tname'] = self.__class__.__name__ for f in dataclasses.fields(self): f_type = f.type value = getattr(self, f.name) if (isinstance(f_type, type) and issubclass(f_type, CompositeConfigType) and value is not None): value = value.to_json_value() elif typing_inspect.is_generic_type(f_type): value = list(value) dct[f.name] = value return dct