Merge pull request #21276 from gavindsouza/bump-pydantic-v2

build(deps): Bump Pydantic from v1 to v2
This commit is contained in:
mergify[bot] 2023-07-02 13:38:18 +00:00 committed by GitHub
commit 721035b313
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 31 deletions

View file

@ -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

View file

@ -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")

View file

@ -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)

View file

@ -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",