def test_between_3_and_50_characters(self):
        f = Field(..., min_length=3, max_length=50)
        field = ModelField(
            name="name",
            type_=str,
            class_validators={},
            field_info=f,
            model_config=BaseConfig,
        )
        long_text = "Lorem Ipsum is simply dummy text of\
                the printing and typesetting industry. "

        with pytest.raises(ValueError):

            PartialUser.between_3_and_50_characters("He", field=field)

        with pytest.raises(ValueError):
            PartialUser.between_3_and_50_characters(
                long_text,
                field=field,
            )
        assert PartialUser.between_3_and_50_characters("Hello") == "Hello"
Exemple #2
0
async def serialize_response(
    *,
    field: ModelField = None,
    response: Response,
    include: Union[SetIntStr, DictIntStrAny] = None,
    exclude: Union[SetIntStr, DictIntStrAny] = set(),
    by_alias: bool = True,
    exclude_unset: bool = False,
    is_coroutine: bool = True,
) -> Any:
    if field:
        errors = []
        if exclude_unset and isinstance(response, BaseModel):
            if PYDANTIC_1:
                response = response.dict(exclude_unset=exclude_unset)
            else:
                response = response.dict(
                    skip_defaults=exclude_unset)  # pragma: nocover
        if is_coroutine:
            value, errors_ = field.validate(response, {}, loc=("response", ))
        else:
            value, errors_ = await run_in_threadpool(field.validate,
                                                     response, {},
                                                     loc=("response", ))
        if isinstance(errors_, ErrorWrapper):
            errors.append(errors_)
        elif isinstance(errors_, list):
            errors.extend(errors_)
        if errors:
            raise ValidationError(errors, field.type_)
        return jsonable_encoder(
            value,
            include=include,
            exclude=exclude,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
        )
    else:
        return jsonable_encoder(response)
Exemple #3
0
def create_pydantic_field(
    field_name: str, model: Type["Model"], model_field: Type["ManyToManyField"]
) -> None:
    """
    Registers pydantic field on through model that leads to passed model
    and is registered as field_name passed.

    Through model is fetched from through attributed on passed model_field.

    :param field_name: field name to register
    :type field_name: str
    :param model: type of field to register
    :type model: Model class
    :param model_field: relation field from which through model is extracted
    :type model_field: ManyToManyField class
    """
    model_field.through.__fields__[field_name] = ModelField(
        name=field_name,
        type_=model,
        model_config=model.__config__,
        required=False,
        class_validators={},
    )
Exemple #4
0
def infer_request_from_annotations(func: Callable) -> Optional[Type[BaseModel]]:
    """Infer an OpenAPI request body from function annotations.

    The annotations are converted to a `BaseModel` and schema is extracted from
    it.

    Args:
        func: The function whose annotations are to be inferred.

    Returns:
        A `BaseModel` generated from the annotation's return value

    """
    annot = {x: y for x, y in func.__annotations__.items() if x != "return"}
    if annot:
        class Annot(BaseModel):
            pass
        for x, y in annot.items():
            Annot.__fields__[x] = ModelField(name=x, type_=y, class_validators={},
                                             model_config=BaseConfig,
                                             required=True)
        return Annot
    else:
        return None
async def serialize_response(
    *,
    field: ModelField = None,
    response_content: Any,
    include: Union[SetIntStr, DictIntStrAny] = None,
    exclude: Union[SetIntStr, DictIntStrAny] = set(),
    by_alias: bool = True,
    exclude_unset: bool = False,
    is_coroutine: bool = True,
) -> Any:
    if field:
        errors = []
        response_content = _prepare_response_content(
            response_content, by_alias=by_alias, exclude_unset=exclude_unset
        )
        if is_coroutine:
            value, errors_ = field.validate(response_content, {}, loc=("response",))
        else:
            value, errors_ = await run_in_threadpool(
                field.validate, response_content, {}, loc=("response",)
            )
        if isinstance(errors_, ErrorWrapper):
            errors.append(errors_)
        elif isinstance(errors_, list):
            errors.extend(errors_)
        if errors:
            raise ValidationError(errors, field.type_)
        return jsonable_encoder(
            value,
            include=include,
            exclude=exclude,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
        )
    else:
        return jsonable_encoder(response_content)
Exemple #6
0
    def _check_param(
        cls, dependent: Dependent, name: str, param: inspect.Parameter
    ) -> Optional["EventParam"]:
        from nonebot.adapters import Event

        if param.default == param.empty:
            if generic_check_issubclass(param.annotation, Event):
                if param.annotation is not Event:
                    dependent.pre_checkers.append(
                        _EventChecker(
                            Required,
                            field=ModelField(
                                name=name,
                                type_=param.annotation,
                                class_validators=None,
                                model_config=CustomConfig,
                                default=None,
                                required=True,
                            ),
                        )
                    )
                return cls(Required)
            elif param.annotation == param.empty and name == "event":
                return cls(Required)
Exemple #7
0
def create_cloned_field(field: ModelField) -> ModelField:
    original_type = field.type_
    if is_dataclass(original_type) and hasattr(original_type, "__pydantic_model__"):
        original_type = original_type.__pydantic_model__  # type: ignore
    use_type = original_type
    if lenient_issubclass(original_type, BaseModel):
        original_type = cast(Type[BaseModel], original_type)
        use_type = create_model(
            original_type.__name__, __config__=original_type.__config__
        )
        for f in original_type.__fields__.values():
            use_type.__fields__[f.name] = f
        use_type.__validators__ = original_type.__validators__
    if PYDANTIC_1:
        new_field = ModelField(
            name=field.name,
            type_=use_type,
            class_validators={},
            default=None,
            required=False,
            model_config=BaseConfig,
            field_info=FieldInfo(None),
        )
    else:  # pragma: nocover
        new_field = ModelField(  # type: ignore
            name=field.name,
            type_=use_type,
            class_validators={},
            default=None,
            required=False,
            model_config=BaseConfig,
            schema=FieldInfo(None),
        )
    new_field.has_alias = field.has_alias
    new_field.alias = field.alias
    new_field.class_validators = field.class_validators
    new_field.default = field.default
    new_field.required = field.required
    new_field.model_config = field.model_config
    if PYDANTIC_1:
        new_field.field_info = field.field_info
    else:  # pragma: nocover
        new_field.schema = field.schema  # type: ignore
    new_field.allow_none = field.allow_none
    new_field.validate_always = field.validate_always
    if field.sub_fields:
        new_field.sub_fields = [
            create_cloned_field(sub_field) for sub_field in field.sub_fields
        ]
    if field.key_field:
        new_field.key_field = create_cloned_field(field.key_field)
    new_field.validators = field.validators
    if PYDANTIC_1:
        new_field.pre_validators = field.pre_validators
        new_field.post_validators = field.post_validators
    else:  # pragma: nocover
        new_field.whole_pre_validators = field.whole_pre_validators  # type: ignore
        new_field.whole_post_validators = field.whole_post_validators  # type: ignore
    new_field.parse_json = field.parse_json
    new_field.shape = field.shape
    try:
        new_field.populate_validators()
    except AttributeError:  # pragma: nocover
        # TODO: remove when removing support for Pydantic < 1.0.0
        new_field._populate_validators()  # type: ignore
    return new_field
Exemple #8
0
def get_param_field(
    *,
    param: inspect.Parameter,
    param_name: str,
    default_field_info: Type[params.Param] = params.Param,
    force_type: params.ParamTypes = None,
    ignore_default: bool = False,
) -> ModelField:
    default_value = Required
    had_schema = False
    if not param.default == param.empty and ignore_default is False:
        default_value = param.default
    if isinstance(default_value, FieldInfo):
        had_schema = True
        field_info = default_value
        default_value = field_info.default
        if (isinstance(field_info, params.Param)
                and getattr(field_info, "in_", None) is None):
            field_info.in_ = default_field_info.in_
        if force_type:
            field_info.in_ = force_type  # type: ignore
    else:
        field_info = default_field_info(default_value)
    required = default_value == Required
    annotation: Any = Any
    if not param.annotation == param.empty:
        annotation = param.annotation
    annotation = get_annotation_from_field_info(annotation, field_info,
                                                param_name)
    if not field_info.alias and getattr(field_info, "convert_underscores",
                                        None):
        alias = param.name.replace("_", "-")
    else:
        alias = field_info.alias or param.name
    if PYDANTIC_1:
        field = ModelField(
            name=param.name,
            type_=annotation,
            default=None if required else default_value,
            alias=alias,
            required=required,
            model_config=BaseConfig,
            class_validators={},
            field_info=field_info,
        )
        # TODO: remove when removing support for Pydantic < 1.2.0
        field.required = required
    else:  # pragma: nocover
        field = ModelField(  # type: ignore
            name=param.name,
            type_=annotation,
            default=None if required else default_value,
            alias=alias,
            required=required,
            model_config=BaseConfig,
            class_validators={},
            schema=field_info,
        )
        field.required = required
    if not had_schema and not is_scalar_field(field=field):
        if PYDANTIC_1:
            field.field_info = params.Body(field_info.default)
        else:
            field.schema = params.Body(
                field_info.default)  # type: ignore  # pragma: nocover

    return field
Exemple #9
0
        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)
Exemple #10
0
DEFAULT_DATA = [
    {
        "__ejsorm__": "generated",
        "__temp__": []
    },
    {
        "__table__": "__other",
        "__data__": {}
    },
]

PK_FIELD = ModelField(
    name=EJ_OBJECT_ID_FIELD,
    type_=int,
    required=True,
    model_config=BaseConfig,
    class_validators=None,
)


class Ejsorm:
    def __init__(self, path: str):
        if not path.endswith(".json"):
            raise EJError(f"Path must has .json file extension, got {path}")
        self.path = path
        self._data: typing.Optional[EJData] = None

    @property
    def data(self) -> EJData:
        if self._data is None:
Exemple #11
0
def check_field_type(field: ModelField, value: V) -> V:
    _, errs_ = field.validate(value, {}, loc=())
    if errs_:
        raise TypeMisMatch(field, value)
    return value
Exemple #12
0
    def __init__(
        self,
        path: str,
        endpoint: Callable,
        *,
        response_model: Type[Any] = None,
        status_code: int = 200,
        tags: List[str] = None,
        dependencies: Sequence[params.Depends] = None,
        summary: str = None,
        description: str = None,
        response_description: str = "Successful Response",
        responses: Dict[Union[int, str], Dict[str, Any]] = None,
        deprecated: bool = None,
        name: str = None,
        methods: Optional[Union[Set[str], List[str]]] = None,
        operation_id: str = None,
        response_model_include: Union[SetIntStr, DictIntStrAny] = None,
        response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(),
        response_model_by_alias: bool = True,
        response_model_exclude_unset: bool = False,
        include_in_schema: bool = True,
        response_class: Optional[Type[Response]] = None,
        dependency_overrides_provider: Any = None,
    ) -> None:
        self.path = path
        self.endpoint = endpoint
        self.name = get_name(endpoint) if name is None else name
        self.path_regex, self.path_format, self.param_convertors = compile_path(
            path)
        if methods is None:
            methods = ["GET"]
        self.methods = set([method.upper() for method in methods])
        self.unique_id = generate_operation_id_for_path(
            name=self.name, path=self.path_format, method=list(methods)[0])
        self.response_model = response_model
        if self.response_model:
            assert (
                status_code not in STATUS_CODES_WITH_NO_BODY
            ), f"Status code {status_code} must not have a response body"
            response_name = "Response_" + self.unique_id
            if PYDANTIC_1:
                self.response_field: Optional[ModelField] = ModelField(
                    name=response_name,
                    type_=self.response_model,
                    class_validators={},
                    default=None,
                    required=False,
                    model_config=BaseConfig,
                    field_info=FieldInfo(None),
                )
            else:
                self.response_field: Optional[
                    ModelField] = ModelField(  # type: ignore  # pragma: nocover
                        name=response_name,
                        type_=self.response_model,
                        class_validators={},
                        default=None,
                        required=False,
                        model_config=BaseConfig,
                        schema=FieldInfo(None),
                    )
            # Create a clone of the field, so that a Pydantic submodel is not returned
            # as is just because it's an instance of a subclass of a more limited class
            # e.g. UserInDB (containing hashed_password) could be a subclass of User
            # that doesn't have the hashed_password. But because it's a subclass, it
            # would pass the validation and be returned as is.
            # By being a new field, no inheritance will be passed as is. A new model
            # will be always created.
            self.secure_cloned_response_field: Optional[
                ModelField] = create_cloned_field(self.response_field)
        else:
            self.response_field = None
            self.secure_cloned_response_field = None
        self.status_code = status_code
        self.tags = tags or []
        if dependencies:
            self.dependencies = list(dependencies)
        else:
            self.dependencies = []
        self.summary = summary
        self.description = description or inspect.cleandoc(
            self.endpoint.__doc__ or "")
        # if a "form feed" character (page break) is found in the description text,
        # truncate description text to the content preceding the first "form feed"
        self.description = self.description.split("\f")[0]
        self.response_description = response_description
        self.responses = responses or {}
        response_fields = {}
        for additional_status_code, response in self.responses.items():
            assert isinstance(response,
                              dict), "An additional response must be a dict"
            model = response.get("model")
            if model:
                assert (
                    additional_status_code not in STATUS_CODES_WITH_NO_BODY
                ), f"Status code {additional_status_code} must not have a response body"
                assert lenient_issubclass(
                    model,
                    BaseModel), "A response model must be a Pydantic model"
                response_name = f"Response_{additional_status_code}_{self.unique_id}"
                if PYDANTIC_1:
                    response_field = ModelField(
                        name=response_name,
                        type_=model,
                        class_validators=None,
                        default=None,
                        required=False,
                        model_config=BaseConfig,
                        field_info=FieldInfo(None),
                    )
                else:
                    response_field = ModelField(  # type: ignore  # pragma: nocover
                        name=response_name,
                        type_=model,
                        class_validators=None,
                        default=None,
                        required=False,
                        model_config=BaseConfig,
                        schema=FieldInfo(None),
                    )
                response_fields[additional_status_code] = response_field
        if response_fields:
            self.response_fields: Dict[Union[int, str],
                                       ModelField] = response_fields
        else:
            self.response_fields = {}
        self.deprecated = deprecated
        self.operation_id = operation_id
        self.response_model_include = response_model_include
        self.response_model_exclude = response_model_exclude
        self.response_model_by_alias = response_model_by_alias
        self.response_model_exclude_unset = response_model_exclude_unset
        self.include_in_schema = include_in_schema
        self.response_class = response_class

        assert inspect.isfunction(endpoint) or inspect.ismethod(
            endpoint), f"An endpoint must be a function or method"
        self.dependant = get_dependant(path=self.path_format,
                                       call=self.endpoint)
        for depends in self.dependencies[::-1]:
            self.dependant.dependencies.insert(
                0,
                get_parameterless_sub_dependant(depends=depends,
                                                path=self.path_format),
            )
        self.body_field = get_body_field(dependant=self.dependant,
                                         name=self.unique_id)
        self.dependency_overrides_provider = dependency_overrides_provider
        self.app = request_response(self.get_route_handler())
Exemple #13
0
async def serialize_response(
    *,
    field: ModelField = None,
    response_content: Any,
    include: Union[SetIntStr, DictIntStrAny] = None,
    exclude: Union[SetIntStr, DictIntStrAny] = set(),
    by_alias: bool = True,
    exclude_unset: bool = False,
    exclude_defaults: bool = False,
    exclude_none: bool = False,
    is_coroutine: bool = True,
    skip_jsonable_encoder: bool = False,
    skip_validation: bool = False,
) -> Any:
    if field:
        errors = []
        response_content = _prepare_response_content(
            response_content,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
        )
        if skip_validation:
            # If include is explicitly set, then never skip jsonable_encoder
            #
            # _prepare_response_content emits a decoded dict/list python datastructure.
            # It however doesn't complete or coerce any types, so can only be used when
            #  explicitly specifying that one knows what one is doing, and disabling validation
            #
            # If you trust the encoder to handle all your types then we can just return
            #  the output of _prepare_response_content here
            if include is None and skip_jsonable_encoder is True:
                return response_content

            value = response_content
        else:
            if is_coroutine:
                value, errors_ = field.validate(response_content, {},
                                                loc=("response", ))
            else:
                value, errors_ = await run_in_threadpool(field.validate,
                                                         response_content, {},
                                                         loc=("response", ))
            if isinstance(errors_, ErrorWrapper):
                errors.append(errors_)
            elif isinstance(errors_, list):
                errors.extend(errors_)
            if errors:
                raise ValidationError(errors, field.type_)
        return jsonable_encoder(
            value,
            include=include,
            exclude=exclude,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
        )
    else:
        # If you trust the encoder to handle all your types then we can just return
        #  the output of _prepare_response_content here
        return (response_content if skip_jsonable_encoder else
                jsonable_encoder(response_content))