def __call__(self, **kwargs): try: if self._type().id_name() in kwargs: return self._registry(self._type()).find( kwargs[self._type().id_name()]).to_dict( force_all=self._kernel.is_admin(self._context)) except KeyError: raise ffd.MissingArgument(self._type().id_name()) limit = None offset = None if 'limit' in kwargs and 'offset' in kwargs: limit = int(kwargs.get('limit')) offset = int(kwargs.get('offset')) entities = self._registry(self._type()) if 'criteria' in kwargs: criteria = kwargs.get('criteria') if isinstance(criteria, str): criteria = self._serializer.deserialize(criteria) criteria = ffd.BinaryOp.from_dict(criteria) if '__include_deleted' not in kwargs and hasattr( self._type(), 'deleted_on'): criteria &= ffd.Attr('deleted_on').is_none() entities = self._registry(self._type()).filter(criteria) elif '__include_deleted' not in kwargs and hasattr( self._type(), 'deleted_on'): criteria = ffd.Attr('deleted_on').is_none() entities = self._registry(self._type()).filter(criteria) paginated = False count = None if limit is not None and offset is not None: count = len(entities) entities = entities[offset:(offset + limit - 1)] paginated = True if 'sort' in kwargs: entities = entities.sort(lambda x: kwargs.get('sort')) if paginated: return { 'offset': offset, 'limit': limit, 'count': count, 'data': list( map( lambda e: e.to_dict(force_all=self._kernel.is_admin( self._context)), entities)), } return list( map( lambda e: e.to_dict(force_all=self._kernel.is_admin( self._context)), entities))
def __call__(self, **kwargs): try: if 'criteria' in kwargs: return self._registry(self._type()).filter( ffd.BinaryOp.from_dict(kwargs['criteria'])) else: return self._registry(self._type()) except KeyError: raise ffd.MissingArgument(self._type().id_name())
def __call__(self, **kwargs): try: aggregate = self._registry(self._type()).find( kwargs[self._aggregate_name_snake()]) except KeyError: raise ffd.MissingArgument(self._aggregate_name_snake()) method = getattr(aggregate, self._method) return self._buffer_events( method(**ffd.build_argument_list(kwargs, method)))
def _build_value_object(obj, type_, required): try: if isinstance(obj, type_): return obj except TypeError: pass try: e = _generate_model(obj, type_) if e is False and required is True: raise ffd.MissingArgument() return e except ffd.MissingArgument: if required is False: return raise
def _generate_model(args: dict, model_type: type, strict: bool = False): subclasses = model_type.__subclasses__() if len(subclasses): for subclass in subclasses: try: return _generate_model(args, subclass, strict=True) except (RuntimeError, ffd.MissingArgument): continue entity_args = build_argument_list(args, model_type, strict=False) fields_ = {f.name: f for f in fields(model_type)} if strict: for k in args.keys(): if k not in entity_args and k in fields_ and fields_[ k].metadata.get('required', True) is True: raise RuntimeError() if len(entity_args.keys()) == 0: raise ffd.MissingArgument() return model_type(**entity_args)
def _handle_type_hint(params: typing.Any, t: type, key: str = None, required: bool = False): # logging.debug('Processing type hint %s with params: %s, key: %s, required: %s', t, params, key, required) ret = {} origin = ffd.get_origin(t) args = ffd.get_args(t) if origin is typing.List: if key not in params: if required: raise ffd.MissingArgument( f'Missing argument {key} for type {t}') return [] if ffd.is_type_hint(args[0]): if key is not None: ret[key] = list( map(lambda a: _handle_type_hint(a, args[0]), params[key])) else: ret = list( map(lambda a: _handle_type_hint(a, args[0]), params[key])) elif inspect.isclass(args[0]) and issubclass(args[0], ffd.ValueObject): try: if key is not None: ret[key] = [] for v in params[key]: parameter = _build_value_object(v, args[0], required) if parameter is not None: ret[key].append(parameter) if len(ret[key]) == 0: del ret[key] else: ret = list( map( lambda a: _build_value_object( a, args[0], required), params[key])) except TypeError: return else: ret[key] = params[key] elif origin is typing.Dict: if key not in params: if required: raise ffd.MissingArgument() return {} if ffd.is_type_hint(args[1]): ret[key] = { k: _handle_type_hint(v, args[1]) for k, v in params[key].items() } elif inspect.isclass(args[1]) and issubclass(args[1], ffd.ValueObject): ret[key] = { k: _build_value_object(v, args[1], required) for k, v in params[key].items() } else: ret[key] = params[key] elif origin is typing.Union: for arg in args: # logging.debug('Calling _handle_type_hint') r = _handle_type_hint(params, arg, key, required) # logging.debug('Response: %s', r) if r is not void: if key is not None: ret[key] = r else: ret = r break else: if inspect.isclass(t) and issubclass(t, ffd.ValueObject): if key in params: return _build_value_object(params[key], t, required) else: return _build_value_object(params, t, required) try: if key is not None: if key in params: val = _check_special_types(params[key], t) if val is not None: return val try: if t(params[key]) == params[key]: return params[key] except ValueError: pass if params[key] is None: return None elif str(t) == "<class 'NoneType'>": return None elif key is None and t(params) == params: return params except (TypeError, KeyError): pass if ret == {}: return void return ret
def build_argument_list(params: dict, obj: typing.Union[typing.Callable, type], strict: bool = True, include_none_parameters: bool = False): # logging.debug('Building argument list for %s with params: %s, strict: %s', obj, params, strict) args = {} field_dict = {} is_dc = False params = _fix_keywords(params) if is_dataclass(obj): is_dc = True field_dict = {} # noinspection PyDataclass for field_ in fields(obj): field_dict[field_.name] = field_ sig = inspect.signature(obj.__init__) types = typing.get_type_hints(obj) elif isinstance(obj, ffd.MetaAware): sig = inspect.signature(obj.__call__) types = typing.get_type_hints(obj.__call__) elif isinstance(obj, type): sig = inspect.signature(obj.__init__) types = typing.get_type_hints(obj.__init__) else: sig = inspect.signature(obj) try: types = typing.get_type_hints(obj) except NameError: types = obj.__annotations__ has_kwargs = False for param in sig.parameters.values(): if param.kind == inspect.Parameter.VAR_KEYWORD: has_kwargs = True # return params for name, param in sig.parameters.items(): # logging.debug('Processing param %s', param) if name == 'self' or param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD): # logging.debug('Skipping...') continue required = False if is_dc: required = field_dict[name].metadata.get('required', False) is True try: d = field_dict[name].default_factory() if not isinstance(d, ffd.Empty): required = False except (AttributeError, TypeError): pass elif param.default == inspect.Parameter.empty: required = True type_ = types[name] if name in types else None if params and name in params: val = _check_special_types(params[name], type_) if val is not None: params[name] = val if isinstance(type_, type) and issubclass(type_, ffd.ValueObject): if params is None: if required is False: continue raise ffd.MissingArgument(name) if name in params and isinstance(params[name], type_): args[name] = params[name] continue try: nested = False e = None if name in params and isinstance(params[name], dict): e = _generate_model(params[name], type_) nested = True elif isinstance(params, dict): e = _generate_model(copy_params(params, sig), type_) except ffd.MissingArgument: if required is False: continue raise # TODO use factories where appropriate args[name] = e if nested: del params[name] elif ffd.is_type_hint(type_): if type_ is typing.Any: if name in params: args[name] = params[name] else: if name in params: parameter_args = _handle_type_hint({name: params[name]}, type_, key=name, required=required) elif isinstance(params, dict): parameter_args = _handle_type_hint(copy_params( params, sig), type_, key=name, required=required) if parameter_args and not isinstance(parameter_args, Void): args.update(parameter_args) elif isinstance(params, dict) and name in params: try: if params[name] is None: if not is_dc or include_none_parameters is True: args[name] = None elif isinstance(params[name], bytes): args[name] = params[name] else: try: args[name] = type_(params[name]) except OverflowError: args[name] = params[name] except TypeError: args[name] = params[name] elif name.endswith('_') and name.rstrip('_') in params: # args[name] = params[name.rstrip('_')] try: sname = name.rstrip('_') if params[sname] is None: if not is_dc or include_none_parameters is True: args[name] = None elif isinstance(params[sname], bytes): args[name] = params[sname] else: try: args[name] = type_(params[sname]) except OverflowError: args[name] = params[name] except TypeError: args[name] = params[name.rstrip('_')] elif required is True and strict: raise ffd.MissingArgument( f'Argument: {name} is required for object {obj}') if has_kwargs: for k, v in params.items(): if k not in args: args[k] = v # logging.debug('Returning %s', args) return args
def build_argument_list(params: dict, obj: typing.Union[typing.Callable, type]): args = {} field_dict = {} is_dc = False params = _fix_keywords(params) if is_dataclass(obj): is_dc = True field_dict = {} # noinspection PyDataclass for field_ in fields(obj): field_dict[field_.name] = field_ sig = inspect.signature(obj.__init__) types = typing.get_type_hints(obj) elif isinstance(obj, ffd.MetaAware): sig = inspect.signature(obj.__call__) types = typing.get_type_hints(obj.__call__) elif isinstance(obj, type): sig = inspect.signature(obj.__init__) types = typing.get_type_hints(obj.__init__) else: sig = inspect.signature(obj) try: types = typing.get_type_hints(obj) except NameError: types = obj.__annotations__ for param in sig.parameters.values(): if param.kind == inspect.Parameter.VAR_KEYWORD: return params for name, param in sig.parameters.items(): if name == 'self' or param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD): continue required = False if is_dc: required = field_dict[name].metadata.get('required', False) is True try: d = field_dict[name].default_factory() if not isinstance(d, ffd.Empty): required = False except (AttributeError, TypeError): pass elif param.default is not None: required = True type_ = types[name] if name in types else None if type_ is datetime and name in params and isinstance(params[name], str): params[name] = parse(params[name]).replace(tzinfo=None) if isinstance(type_, type) and issubclass(type_, ffd.ValueObject): if name in params and isinstance(params[name], type_): args[name] = params[name] continue try: nested = False if name in params and isinstance(params[name], dict): entity_args = build_argument_list(params[name], type_) nested = True else: entity_args = build_argument_list(params, type_) except ffd.MissingArgument: if required is False: continue raise # TODO use factories where appropriate args[name] = type_(**entity_args) if nested: del params[name] else: for key in entity_args.keys(): if not hasattr(type_, 'id_name') or key != type_.id_name(): del params[key] if key in args: del args[key] elif isinstance(type_, type(typing.List)) and issubclass(type_.__args__[0], ffd.ValueObject): args[name] = [] if isinstance(params, dict) and name in params: for d in params[name]: try: entity_args = build_argument_list(d, type_.__args__[0]) except ffd.MissingArgument: if required is False: continue raise args[name].append(type_.__args__[0](**entity_args)) elif isinstance(type_, type(typing.Dict)) and len(type_.__args__) == 2 and \ issubclass(type_.__args__[1], ffd.ValueObject): args[name] = {} if isinstance(params, dict) and name in params: for k, d in params[name].items(): try: entity_args = build_argument_list(d, type_.__args__[1]) except ffd.MissingArgument: if required is False: continue raise args[name][k] = type_.__args__[1](**entity_args) elif isinstance(params, dict) and name in params: args[name] = params[name] elif name.endswith('_') and name.rstrip('_') in params: args[name] = params[name.rstrip('_')] elif required is True: raise ffd.MissingArgument(f'Argument: {name} is required') return args