def _init_cbv(cls: Type[Any]) -> None: """ Idempotently modifies the provided `cls`, performing the following modifications: * The `__init__` function is updated to set any class-annotated dependencies as instance attributes * The `__signature__` attribute is updated to indicate to FastAPI what arguments should be passed to the initializer """ if getattr(cls, CBV_CLASS_KEY, False): # pragma: no cover return # Already initialized old_init: Callable[..., Any] = cls.__init__ old_signature = inspect.signature(old_init) old_parameters = list(old_signature.parameters.values())[1:] # drop `self` parameter new_parameters = [ x for x in old_parameters if x.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD) ] dependency_names: List[str] = [] for name, hint in get_type_hints(cls).items(): if is_classvar(hint): continue parameter_kwargs = {"default": getattr(cls, name, Ellipsis)} dependency_names.append(name) new_parameters.append( inspect.Parameter(name=name, kind=inspect.Parameter.KEYWORD_ONLY, annotation=hint, **parameter_kwargs) ) new_signature = old_signature.replace(parameters=new_parameters) def new_init(self: Any, *args: Any, **kwargs: Any) -> None: for dep_name in dependency_names: dep_value = kwargs.pop(dep_name) setattr(self, dep_name, dep_value) old_init(self, *args, **kwargs) setattr(cls, "__signature__", new_signature) setattr(cls, "__init__", new_init) setattr(cls, CBV_CLASS_KEY, True)
def _init_obj(self) -> None: """fork from https://github.com/dmontagu/fastapi-utils/blob/master/fastapi_utils/cbv.py#L53""" cls = self._obj old_init: Callable[..., Any] = cls.__init__ old_signature = inspect.signature(old_init) old_parameters = list( old_signature.parameters.values())[1:] # drop `self` parameter new_parameters = [ x for x in old_parameters if x.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD) ] dependency_names: List[str] = [] for name, hint in get_type_hints(cls).items(): if is_classvar(hint): continue parameter_kwargs = {"default": getattr(cls, name, Ellipsis)} dependency_names.append(name) new_parameters.append( inspect.Parameter(name=name, kind=inspect.Parameter.KEYWORD_ONLY, annotation=hint, **parameter_kwargs)) new_signature = old_signature.replace(parameters=new_parameters) setattr(cls, "__signature__", new_signature) def new_init(_self: Any, *args: Any, **kwargs: Any) -> None: for dep_name in dependency_names: dep_value = kwargs.pop(dep_name) setattr(_self, dep_name, dep_value) old_init(_self, *args, **kwargs) setattr(cls, "__init__", new_init)
def _init_cbv(cls: Type[Any]) -> None: if getattr(cls, CBV_CLASS_KEY, False): # pragma: no cover return # Already initialized old_init: Callable[..., Any] = cls.__init__ old_signature = inspect.signature(old_init) old_parameters = list( old_signature.parameters.values())[1:] # drop `self` parameter new_parameters = [ x for x in old_parameters if x.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD) ] dependency_names: List[str] = [] for name, hint in get_type_hints(cls).items(): if is_classvar(hint): continue parameter_kwargs = {} parameter_kwargs["default"] = getattr(cls, name, Ellipsis) dependency_names.append(name) new_parameters.append( inspect.Parameter(name=name, kind=inspect.Parameter.KEYWORD_ONLY, annotation=hint, **parameter_kwargs)) new_signature = old_signature.replace(parameters=new_parameters) def new_init(self: Any, *args: Any, **kwargs: Any) -> None: for dep_name in dependency_names: dep_value = kwargs.pop(dep_name) setattr(self, dep_name, dep_value) old_init(self, *args, **kwargs) setattr(cls, "__signature__", new_signature) setattr(cls, "__init__", new_init) setattr(cls, CBV_CLASS_KEY, True)
def from_class_attributes(cls, clazz: Type) -> Iterable["RequestCtxParam"]: for name, hint in get_type_hints(clazz).items(): if is_classvar(hint): continue value = getattr(clazz, name, _undefined) if isinstance(value, ParamTypeSet): yield RequestCtxParam(name, hint, value) elif isinstance(value, RequestCtxParam): yield value.clone()
def should_touch_field(value: Any = None, type_: Optional[Type] = None) -> bool: return not (lenient_issubclass(type_, UNTOUCHED_TYPES) or isinstance(value, UNTOUCHED_TYPES) or (type_ is not None and is_classvar(type_)))
def __new__(mcs, name, bases, namespace, **kwargs): from pydantic.fields import Undefined from pydantic.class_validators import extract_validators, inherit_validators from pydantic.types import PyObject from pydantic.typing import is_classvar, resolve_annotations from pydantic.utils import lenient_issubclass, validate_field_name from pydantic.main import inherit_config, prepare_config, UNTOUCHED_TYPES fields: Dict[str, ModelField] = {} config = BaseConfig validators: Dict[str, List[Validator]] = {} for base in reversed(bases): if issubclass(base, AbstractCheckedSession) and base != AbstractCheckedSession: config = inherit_config(base.__config__, config) fields.update(deepcopy(base.__fields__)) validators = inherit_validators(base.__validators__, validators) config = inherit_config(namespace.get('Config'), config) validators = inherit_validators(extract_validators(namespace), validators) # update fields inherited from base classes for field in fields.values(): field.set_config(config) extra_validators = validators.get(field.name, []) if extra_validators: field.class_validators.update(extra_validators) # re-run prepare to add extra validators field.populate_validators() prepare_config(config, name) # extract and build fields class_vars = set() if (namespace.get('__module__'), namespace.get('__qualname__')) != \ ('larray.core.checked', 'CheckedSession'): untouched_types = UNTOUCHED_TYPES + config.keep_untouched # annotation only fields need to come first in fields annotations = resolve_annotations(namespace.get('__annotations__', {}), namespace.get('__module__', None)) for ann_name, ann_type in annotations.items(): if is_classvar(ann_type): class_vars.add(ann_name) elif not ann_name.startswith('_'): validate_field_name(bases, ann_name) value = namespace.get(ann_name, Undefined) if (isinstance(value, untouched_types) and ann_type != PyObject and not lenient_issubclass(getattr(ann_type, '__origin__', None), Type)): continue fields[ann_name] = ModelField.infer(name=ann_name, value=value, annotation=ann_type, class_validators=validators.get(ann_name, []), config=config) for var_name, value in namespace.items(): # 'var_name not in annotations' because namespace.items() contains annotated fields # with default values # 'var_name not in class_vars' to avoid to update a field if it was redeclared (by mistake) if (var_name not in annotations and not var_name.startswith('_') and not isinstance(value, untouched_types) and var_name not in class_vars): validate_field_name(bases, var_name) # the method ModelField.infer() fails to infer the type of Group objects # (which are interpreted as ndarray objects) annotation = type(value) if isinstance(value, Group) else annotations.get(var_name) inferred = ModelField.infer(name=var_name, value=value, annotation=annotation, class_validators=validators.get(var_name, []), config=config) if var_name in fields and inferred.type_ != fields[var_name].type_: raise TypeError(f'The type of {name}.{var_name} differs from the new default value; ' f'if you wish to change the type of this field, please use a type ' f'annotation') fields[var_name] = inferred new_namespace = { '__config__': config, '__fields__': fields, '__field_defaults__': {n: f.default for n, f in fields.items() if not f.required}, '__validators__': validators, **{n: v for n, v in namespace.items() if n not in fields}, } return super().__new__(mcs, name, bases, new_namespace, **kwargs)