def _from_dict_special_cases( cls: Type[BaseModel], param: str, param_type: Type[Any], param_value: Dict[str, Any], ) -> Union[str, Enum, BaseModel, Dict[str, Any]]: """Handles all the recursive/more complex cases for `from_dict`.""" from xrpl.models.amounts import Amount, IssuedCurrencyAmount from xrpl.models.currencies import XRP, Currency, IssuedCurrency from xrpl.models.transactions.transaction import Transaction # TODO: figure out how to make Unions work generically (if possible) if param_type == Amount: # special case, Union if isinstance(param_value, str): return param_value if not isinstance(param_value, dict): raise XRPLModelException( f"{param_type} requires a dictionary of params") return IssuedCurrencyAmount.from_dict(param_value) if param_type == Currency: # special case, Union if not isinstance(param_value, dict): raise XRPLModelException( f"{param_type} requires a dictionary of params") if "currency" in param_value and "issuer" in param_value: return IssuedCurrency.from_dict(param_value) if "currency" in param_value: param_value_copy = {**param_value} del param_value_copy["currency"] return XRP.from_dict(param_value_copy) raise XRPLModelException(f"No valid type for {param}") if param_type == Transaction: # special case, multiple options (could be any Transaction type) if "transaction_type" not in param_value: raise XRPLModelException( f"{param} not a valid parameter for {cls.__name__}") type_str = param_value["transaction_type"] # safely convert type string into the actual type transaction_type = Transaction.get_transaction_type(type_str) param_value_copy = {**param_value} del param_value_copy["transaction_type"] return transaction_type.from_dict(param_value_copy) if param_type in BaseModel.__subclasses__(): # any other BaseModel if not isinstance(param_value, dict): raise XRPLModelException( f"{param_type} requires a dictionary of params") # mypy doesn't know that the If checks that it's a subclass of BaseModel return param_type.from_dict(param_value) # type: ignore if param_type in Enum.__subclasses__(): # mypy doesn't know that the If checks that it's a subclass of Enum return param_type(param_value) # type: ignore return param_value
def _from_dict_single_param( cls: Type[BaseModel], param: str, param_type: Type[Any], param_value: Dict[str, Any], ) -> Any: """Recursively handles each individual param in `from_dict`.""" if type(param_value) == param_type: # the type of the param provided matches the type expected for the param return param_value if "xrpl.models" in param_type.__module__: # any model defined in xrpl.models if not isinstance(param_value, dict): raise XRPLModelException( f"{param_type} requires a dictionary of params") return cast(BaseModel, param_type).from_dict(param_value) if param_type in Enum.__subclasses__(): # an Enum return param_type(param_value) # param_type must be something from typing - e.g. List, Union, Any # there are no models that have Dict params if param_type == Any: # param_type is Any return param_value if param_type.__reduce__()[1][0] == List: # param_type is a List if not isinstance(param_value, List): raise XRPLModelException( f"{param} expected a List, received a {type(param_value)}") list_type = param_type.__reduce__()[1][1] new_list = [] for item in param_value: new_list.append( cls._from_dict_single_param(param, list_type, item)) return new_list if param_type.__reduce__()[1][0] == Union: # param_type is a Union for param_type_option in param_type.__args__: # iterate through the types Union-ed together try: # try to use this Union-ed type to process param_value return cls._from_dict_single_param(param, param_type_option, param_value) except XRPLModelException: # this Union-ed type did not work # move onto the next one continue raise XRPLModelException( f"{param} expected a {param_type}, received a {type(param_value)}")