Merge pull request #21276 from gavindsouza/bump-pydantic-v2
build(deps): Bump Pydantic from v1 to v2
This commit is contained in:
commit
721035b313
4 changed files with 51 additions and 31 deletions
|
|
@ -33,6 +33,8 @@ _sites_path = os.environ.get("SITES_PATH", ".")
|
|||
|
||||
# If gc.freeze is done then importing modules before forking allows us to share the memory
|
||||
if frappe._tune_gc:
|
||||
import pydantic
|
||||
|
||||
import frappe.boot
|
||||
import frappe.client
|
||||
import frappe.core.doctype.user.user
|
||||
|
|
|
|||
|
|
@ -1163,3 +1163,44 @@ class TestRounding(FrappeTestCase):
|
|||
|
||||
def test_default_rounding(self):
|
||||
self.assertEqual(frappe.get_system_settings("rounding_method"), "Banker's Rounding")
|
||||
|
||||
|
||||
class TestTypingValidations(FrappeTestCase):
|
||||
def test_validate_argument_types(self):
|
||||
from frappe.core.doctype.doctype.doctype import DocType
|
||||
from frappe.utils.typing_validations import FrappeTypeError, validate_argument_types
|
||||
|
||||
@validate_argument_types
|
||||
def test_simple_types(a: int, b: float, c: bool):
|
||||
return a, b, c
|
||||
|
||||
@validate_argument_types
|
||||
def test_sequence(a: str, b: list[dict] | None = None, c: dict[str, int] | None = None):
|
||||
return a, b, c
|
||||
|
||||
@validate_argument_types
|
||||
def test_doctypes(a: DocType | dict):
|
||||
return a
|
||||
|
||||
self.assertEqual(test_simple_types(True, 2.0, True), (1, 2.0, True))
|
||||
self.assertEqual(test_simple_types(1, 2, 1), (1, 2.0, True))
|
||||
self.assertEqual(test_simple_types(1.0, 2, 1), (1, 2.0, True))
|
||||
self.assertEqual(test_simple_types(1, 2, "1"), (1, 2.0, True))
|
||||
with self.assertRaises(FrappeTypeError):
|
||||
test_simple_types(1, 2, "a")
|
||||
with self.assertRaises(FrappeTypeError):
|
||||
test_simple_types(1, 2, None)
|
||||
|
||||
self.assertEqual(test_sequence("a", [{"a": 1}], {"a": 1}), ("a", [{"a": 1}], {"a": 1}))
|
||||
self.assertEqual(test_sequence("a", None, None), ("a", None, None))
|
||||
self.assertEqual(test_sequence("a", [{"a": 1}], None), ("a", [{"a": 1}], None))
|
||||
self.assertEqual(test_sequence("a", None, {"a": 1}), ("a", None, {"a": 1}))
|
||||
self.assertEqual(test_sequence("a", [{"a": 1}], {"a": "1.0"}), ("a", [{"a": 1}], {"a": 1}))
|
||||
with self.assertRaises(FrappeTypeError):
|
||||
test_sequence("a", [{"a": 1}], True)
|
||||
|
||||
doctype = frappe.get_last_doc("DocType")
|
||||
self.assertEqual(test_doctypes(doctype), doctype)
|
||||
self.assertEqual(test_doctypes(doctype.as_dict()), doctype.as_dict())
|
||||
with self.assertRaises(FrappeTypeError):
|
||||
test_doctypes("a")
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
from functools import lru_cache, wraps
|
||||
from inspect import _empty, isclass, signature
|
||||
from types import EllipsisType
|
||||
from typing import Any, Callable, ForwardRef, TypeVar, Union
|
||||
|
||||
from pydantic.config import BaseConfig
|
||||
from pydantic.error_wrappers import ValidationError as PyValidationError
|
||||
from pydantic.tools import NameFactory, _generate_parsing_type_name
|
||||
from typing import Callable, ForwardRef, TypeVar, Union
|
||||
|
||||
from frappe.exceptions import FrappeTypeError
|
||||
|
||||
|
|
@ -69,29 +65,10 @@ def raise_type_error(
|
|||
|
||||
|
||||
@lru_cache(maxsize=2048)
|
||||
def _get_parsing_type(
|
||||
type_: Any, *, type_name: NameFactory | None = None, config: type[BaseConfig] = None
|
||||
) -> Any:
|
||||
# Note: this is a copy of pydantic.tools._get_parsing_type with the addition of allowing a config argument
|
||||
from pydantic.main import create_model
|
||||
def TypeAdapter(type_):
|
||||
from pydantic import TypeAdapter as PyTypeAdapter
|
||||
|
||||
if type_name is None:
|
||||
type_name = _generate_parsing_type_name
|
||||
if not isinstance(type_name, str):
|
||||
type_name = type_name(type_)
|
||||
return create_model(type_name, __root__=(type_, ...), __config__=config)
|
||||
|
||||
|
||||
def parse_obj_as(
|
||||
type_: type[T],
|
||||
obj: Any,
|
||||
*,
|
||||
type_name: NameFactory | None = None,
|
||||
config: type[BaseConfig] | None = None,
|
||||
) -> T:
|
||||
# Note: This is a copy of pydantic.tools.parse_obj_as with the addition of allowing a config argument
|
||||
model_type = _get_parsing_type(type_, type_name=type_name, config=config) # type: ignore[arg-type]
|
||||
return model_type(__root__=obj).__root__
|
||||
return PyTypeAdapter(type_, config=FrappePydanticConfig)
|
||||
|
||||
|
||||
def transform_parameter_types(func: Callable, args: tuple, kwargs: dict):
|
||||
|
|
@ -103,6 +80,8 @@ def transform_parameter_types(func: Callable, args: tuple, kwargs: dict):
|
|||
if not (args or kwargs) or not func.__annotations__:
|
||||
return args, kwargs
|
||||
|
||||
from pydantic import ValidationError as PyValidationError
|
||||
|
||||
annotations = func.__annotations__
|
||||
new_args, new_kwargs = list(args), kwargs
|
||||
|
||||
|
|
@ -157,9 +136,7 @@ def transform_parameter_types(func: Callable, args: tuple, kwargs: dict):
|
|||
|
||||
# validate the type set using pydantic - raise a TypeError if Validation is raised or Ellipsis is returned
|
||||
try:
|
||||
current_arg_value_after = parse_obj_as(
|
||||
current_arg_type, current_arg_value, type_name=current_arg, config=FrappePydanticConfig
|
||||
)
|
||||
current_arg_value_after = TypeAdapter(current_arg_type).validate_python(current_arg_value)
|
||||
except (TypeError, PyValidationError) as e:
|
||||
raise_type_error(current_arg, current_arg_type, current_arg_value, current_exception=e)
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ dependencies = [
|
|||
"psycopg2-binary~=2.9.1",
|
||||
"pyOpenSSL~=23.2.0",
|
||||
"pycryptodome~=3.18.0",
|
||||
"pydantic~=1.10.8",
|
||||
"pydantic==2.0",
|
||||
"pyotp~=2.8.0",
|
||||
"python-dateutil~=2.8.2",
|
||||
"pytz==2023.3",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue