Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimizable field validation #222

Draft
wants to merge 7 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 97 additions & 21 deletions DashAI/back/core/schema_fields/optimizer_float_field.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,95 @@
from typing import Optional, Type
from typing import Any, Callable, Optional, Type

from pydantic import AfterValidator, BaseModel, Field, GetCoreSchemaHandler
from pydantic_core import core_schema
from typing_extensions import Annotated


class OptimizableFloatField(BaseModel):
optimize: bool
fixed_value: float
lower_bound: float
upper_bound: float

@classmethod
def __get_pydantic_core_schema__(
cls, source_type: Any, handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
return core_schema.typed_dict_schema(
{
"optimize": core_schema.typed_dict_field(core_schema.bool_schema()),
"fixed_value": core_schema.typed_dict_field(core_schema.float_schema()),
"lower_bound": core_schema.typed_dict_field(core_schema.float_schema()),
"upper_bound": core_schema.typed_dict_field(core_schema.float_schema()),
},
)


def __check_order_factory(
ge: Optional[int] = None,
gt: Optional[int] = None,
le: Optional[int] = None,
lt: Optional[int] = None,
) -> Callable[[OptimizableFloatField], OptimizableFloatField]:
"""Factory to create custom validator for Optimize float field.
Checks if the input meets the order restrictions.

Parameters
----------
ge: Optional[float]
An optional float that the value should be greater than or equal to.
If not provided, there is no lower limit.
gt: Optional[float]
An optional float that the value should be strictly greater than.
If not provided, there is no strict lower limit.
le: Optional[float]
An optional float that the value should be less than or equal to.
If not provided, there is no upper limit.
lt: Optional[float]
An optional float that the value should be strictly less than.
If not provided, there is no strict upper limit.

Returns
-------
Callable[OptimizableFloatField, OptimizableFloatField]
A function that checks if the input meets the order restrictions.
"""

def check_order(x: OptimizableFloatField) -> OptimizableFloatField:
if ge is not None and (
x["fixed_value"] < ge or x["lower_bound"] < ge or x["upper_bound"] < ge
):
raise ValueError(f"Input should be greater than or equal {ge}")
if gt is not None and (
x["fixed_value"] <= gt or x["lower_bound"] <= gt or x["upper_bound"] <= gt
):
raise ValueError(f"Input should be greater than {gt}")
if le is not None and (
x["fixed_value"] > le or x["lower_bound"] > le or x["upper_bound"] > le
):
raise ValueError(f"Input should be less than or equal {le}")
if lt is not None and (
x["fixed_value"] >= lt or x["lower_bound"] >= le or x["upper_bound"] >= le
):
raise ValueError(f"Input should be less than {le}")
return x

return check_order


def __check_bound_order(x: OptimizableFloatField) -> OptimizableFloatField:
if x["lower_bound"] > x["upper_bound"]:
raise ValueError("lower_bound must be less or equal than upper_bound")
return x


def optimizer_float_field(
ge: Optional[float] = None,
gt: Optional[float] = None,
le: Optional[float] = None,
lt: Optional[float] = None,
) -> Type[float]:
"""Function to create a pydantic-like float type.
ge: Optional[int] = None,
gt: Optional[int] = None,
le: Optional[int] = None,
lt: Optional[int] = None,
) -> Type[OptimizableFloatField]:
"""Function to create a pydantic-like optimizable float type.

Parameters
----------
Expand All @@ -26,18 +108,12 @@ def optimizer_float_field(

Returns
-------
type[float]
A pydantic-like type to represent the float.

Raises
------
ValidationError
If the value of the field is less than the minimum.
ValidationError
If the value of the field is less or equal than the exclusive minimum.
ValidationError
If the value of the field is greater than the maximum.
ValidationError
If the value of the field is greater or equal than the exclusive maximum.
type[OptimizableFloatField]
A pydantic-like type to represent an optimizable float.
"""
return dict
return Annotated[
OptimizableFloatField,
Field(),
AfterValidator(__check_order_factory(ge, gt, le, lt)),
AfterValidator(__check_bound_order),
]
110 changes: 93 additions & 17 deletions DashAI/back/core/schema_fields/optimizer_int_field.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,95 @@
from typing import Optional, Type
from typing import Any, Callable, Optional, Type

from pydantic import AfterValidator, BaseModel, Field, GetCoreSchemaHandler
from pydantic_core import core_schema
from typing_extensions import Annotated


class OptimizableIntField(BaseModel):
optimize: bool
fixed_value: int
lower_bound: int
upper_bound: int

@classmethod
def __get_pydantic_core_schema__(
cls, source_type: Any, handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
return core_schema.typed_dict_schema(
{
"optimize": core_schema.typed_dict_field(core_schema.bool_schema()),
"fixed_value": core_schema.typed_dict_field(core_schema.int_schema()),
"lower_bound": core_schema.typed_dict_field(core_schema.int_schema()),
"upper_bound": core_schema.typed_dict_field(core_schema.int_schema()),
},
)


def __check_order_factory(
ge: Optional[int] = None,
gt: Optional[int] = None,
le: Optional[int] = None,
lt: Optional[int] = None,
) -> Callable[[OptimizableIntField], OptimizableIntField]:
"""Factory to create custom validator for Optimize integer field.
Checks if the input meets the order restrictions.

Parameters
----------
ge: Optional[int]
An optional integer that the value should be greater than or equal to.
If not provided, there is no lower limit.
gt: Optional[int]
An optional integer that the value should be strictly greater than.
If not provided, there is no strict lower limit.
le: Optional[int]
An optional integer that the value should be less than or equal to.
If not provided, there is no upper limit.
lt: Optional[int]
An optional integer that the value should be strictly less than.
If not provided, there is no strict upper limit.

Returns
-------
Callable[OptimizableIntField, OptimizableIntField]
A function that checks if the input meets the order restrictions.
"""

def check_order(x: OptimizableIntField) -> OptimizableIntField:
if ge is not None and (
x["fixed_value"] < ge or x["lower_bound"] < ge or x["upper_bound"] < ge
):
raise ValueError(f"Input should be greater than or equal {ge}")
if gt is not None and (
x["fixed_value"] <= gt or x["lower_bound"] <= gt or x["upper_bound"] <= gt
):
raise ValueError(f"Input should be greater than {gt}")
if le is not None and (
x["fixed_value"] > le or x["lower_bound"] > le or x["upper_bound"] > le
):
raise ValueError(f"Input should be less than or equal {le}")
if lt is not None and (
x["fixed_value"] >= lt or x["lower_bound"] >= le or x["upper_bound"] >= le
):
raise ValueError(f"Input should be less than {le}")
return x

return check_order


def __check_bound_order(x: OptimizableIntField) -> OptimizableIntField:
if x["lower_bound"] > x["upper_bound"]:
raise ValueError("lower_bound must be less or equal than upper_bound")
return x


def optimizer_int_field(
ge: Optional[int] = None,
gt: Optional[int] = None,
le: Optional[int] = None,
lt: Optional[int] = None,
) -> Type[int]:
"""Function to create a pydantic-like integer type.
) -> Type[OptimizableIntField]:
"""Function to create a pydantic-like optimizable integer type.

Parameters
----------
Expand All @@ -26,18 +108,12 @@ def optimizer_int_field(

Returns
-------
type[int]
A pydantic-like type to represent the integer.

Raises
------
ValidationError
If the value of the field is less than the minimum.
ValidationError
If the value of the field is less or equal than the exclusive minimum.
ValidationError
If the value of the field is greater than the maximum.
ValidationError
If the value of the field is greater or equal than the exclusive maximum.
type[OptimizableIntField]
A pydantic-like type to represent an optimizable integer.
"""
return dict
return Annotated[
OptimizableIntField,
Field(),
AfterValidator(__check_order_factory(ge, gt, le, lt)),
AfterValidator(__check_bound_order),
]
78 changes: 39 additions & 39 deletions DashAI/front/src/components/shared/FormSchemaFields.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,50 +35,50 @@ function FormSchemaFields({ objName, paramJsonSchema, field, error }) {
if (!objName) {
return null;
}
if (paramJsonSchema.placeholder?.optimize !== undefined) {
switch (type) {
case "integer":
return (
<OptimizeIntegerInput
{...commonProps}
placeholder={paramJsonSchema.placeholder}
/>
);
case "object":
return (
<OptimizeNumberInput
{...commonProps}
placeholder={paramJsonSchema.placeholder}
/>
);
}
} else {
switch (type) {
case "integer":
return <IntegerInput {...commonProps} />;
case "number":
return <NumberInput {...commonProps} />;
case "string":
if (paramJsonSchema.enum) {
switch (type) {
case "object":
switch (paramJsonSchema.properties?.fixed_value?.type) {
case "integer":
return (
<SelectInput
<OptimizeIntegerInput
{...commonProps}
options={paramJsonSchema.enum}
optionNames={paramJsonSchema.enumNames}
placeholder={paramJsonSchema.placeholder}
/>
);
} else {
return <TextInput {...commonProps} />;
}
case "text":
case "number":
return (
<OptimizeNumberInput
{...commonProps}
placeholder={paramJsonSchema.placeholder}
/>
);
default:
return null;
}
case "integer":
return <IntegerInput {...commonProps} />;
case "number":
return <NumberInput {...commonProps} />;
case "string":
if (paramJsonSchema.enum) {
return (
<SelectInput
{...commonProps}
options={paramJsonSchema.enum}
optionNames={paramJsonSchema.enumNames}
/>
);
} else {
return <TextInput {...commonProps} />;
case "boolean":
return <BooleanInput {...commonProps} />;
case "null" || "undefined":
return <TextInput {...commonProps} disabled />;
default:
return null;
}
}
case "text":
return <TextInput {...commonProps} />;
case "boolean":
return <BooleanInput {...commonProps} />;
case "null" || "undefined":
return <TextInput {...commonProps} disabled />;
default:
return null;
}
}

Expand Down
Loading
Loading