def _get_constructor_args( obj, cls, meta_hints, attr_getters=None, **kwargs) -> dict: # Loop through the signature of cls: the type we try to deserialize to. For # every required parameter, we try to get the corresponding value from # json_obj. signature_parameters = _get_signature(cls) hints = get_type_hints(cls.__init__) attr_getters = dict(**(attr_getters or {})) result = {} for sig_key, sig in signature_parameters.items(): if sig_key != 'self': key, value = _get_value_for_attr(obj=obj, orig_cls=cls, meta_hints=meta_hints, attr_getters=attr_getters, sig_key=sig_key, cls=hints.get(sig_key, None), sig=sig, **kwargs) if key: result[key] = value return result
def test_simple_dump_and_load_dataclass(self): class C: pass hints = get_type_hints(C.__init__) self.assertDictEqual({}, hints)
def _set_remaining_attrs(instance, remaining_attrs, attr_getters, **kwargs): # Set any remaining attributes on the newly created instance. attr_getters = attr_getters or {} for attr_name in remaining_attrs: annotations = get_type_hints(instance.__class__) attr_type = annotations.get(attr_name) if isinstance(remaining_attrs[attr_name], dict) \ and '-keys' in remaining_attrs[attr_name] \ and not attr_type: fork_inst = kwargs['fork_inst'] fork_inst._warn('A dict with -keys was detected without a type ' 'hint for attribute `{}`. This probably means ' 'that you did not provide an annotation in your ' 'class (ending up in __annotations__).' .format(attr_name), 'hashed-keys-without-hint') attr_type = attr_type or type(remaining_attrs[attr_name]) loaded_attr = load(remaining_attrs[attr_name], attr_type, **kwargs) try: setattr(instance, attr_name, loaded_attr) except AttributeError: pass # This is raised when a @property does not have a setter. for attr_name, getter in attr_getters.items(): setattr(instance, attr_name, getter())
def _get_attributes_and_types(cls: type, strict: bool) -> Dict[str, Optional[type]]: if '__slots__' in cls.__dict__: attributes = {attr: None for attr in cls.__slots__} elif hasattr(cls, '__annotations__'): attributes = get_type_hints(cls) elif strict: hints = get_type_hints(cls.__init__) attributes = {k: hints[k] for k in hints if k != 'self'} else: attributes = {} # Add properties and class variables. props, class_vars = _get_class_props(cls) for elem in props + class_vars: attributes[elem] = None return attributes
def test_get_type_hints(self): def get_type_hints_mock(_, globalns=None): if not globalns: raise NameError() get_type_hints_mock.globalns = globalns return {} orig = typing.get_type_hints try: typing.get_type_hints = MagicMock(side_effect=AttributeError) result = get_type_hints(lambda: 42) self.assertEqual({}, result) typing.get_type_hints = get_type_hints_mock result = get_type_hints(lambda: 42, 'builtins') self.assertEqual({}, result) self.assertDictEqual(sys.modules['builtins'].__dict__, get_type_hints_mock.globalns) finally: typing.get_type_hints = orig
def default_namedtuple_deserializer( obj: Union[list, dict], cls: type, *, key_transformer: Optional[Callable[[str], str]] = None, **kwargs) -> object: """ Deserialize a (JSON) list or dict into a named tuple by deserializing all items of that list/dict. :param obj: the tuple that needs deserializing. :param cls: the NamedTuple. :param kwargs: any keyword arguments. :return: a deserialized named tuple (i.e. an instance of a class). """ is_dict = isinstance(obj, dict) key_tfr = key_transformer or (lambda key: key) if is_dict: tfm_obj = {key_tfr(k): v for k, v in obj.items()} args = [] for index, field_name in enumerate(cls._fields): if index < len(obj): if is_dict: field = tfm_obj[field_name] else: field = obj[index] else: field = cls._field_defaults.get(field_name, None) # _field_types has been deprecated in favor of __annotations__ in Python 3.8 if hasattr(cls, '__annotations__'): # It is important to use get_type_hints so that forward references get resolved, # rather than access __annotations__ directly field_types = get_type_hints(cls) else: field_types = getattr(cls, '_field_types', {}) if field is None: hint = field_types.get(field_name) if NoneType not in (get_union_params(hint) or []): # The value 'None' is not permitted here. msg = ('No value present in {} for argument "{}"' .format(obj, field_name)) raise UnfulfilledArgumentError(msg, field_name, obj, cls) cls_ = field_types.get(field_name) if field_types else None loaded_field = load(field, cls_, key_transformer=key_transformer, **kwargs) args.append(loaded_field) inst = cls(*args) return inst
def _get_constructor_args(obj, cls, meta_hints, attr_getters=None, **kwargs) -> dict: # Loop through the signature of cls: the type we try to deserialize to. For # every required parameter, we try to get the corresponding value from # json_obj. signature_parameters = inspect.signature(cls.__init__).parameters hints = get_type_hints(cls.__init__) attr_getters = dict(**(attr_getters or {})) value_for_attr_part = partial(_get_value_for_attr, obj=obj, orig_cls=cls, meta_hints=meta_hints, attr_getters=attr_getters, **kwargs) args_gen = (value_for_attr_part(sig_key=sig_key, cls=hints.get(sig_key, None), sig=sig) for sig_key, sig in signature_parameters.items() if sig_key != 'self') constructor_args_in_obj = {key: value for key, value in args_gen if key} return constructor_args_in_obj
def test_get_type_hints_for_class(self): from test_resources.simple_class_with_hints import C hints = get_type_hints(C) self.assertDictEqual({"x": int}, hints)