mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
ensure cythonized functions are left untouched2 (#2228)
* ensure cythonized functions are left untouched2 * add change
This commit is contained in:
@@ -0,0 +1 @@
|
||||
ensure cythonized functions are left untouched when creating models, based on #1944 by @kollmats
|
||||
+7
-2
@@ -259,6 +259,11 @@ class ModelMetaclass(ABCMeta):
|
||||
|
||||
prepare_config(config, name)
|
||||
|
||||
untouched_types = ANNOTATED_FIELD_UNTOUCHED_TYPES
|
||||
|
||||
def is_untouched(v: Any) -> bool:
|
||||
return isinstance(v, untouched_types) or v.__class__.__name__ == 'cython_function_or_method'
|
||||
|
||||
if (namespace.get('__module__'), namespace.get('__qualname__')) != ('pydantic.main', 'BaseModel'):
|
||||
annotations = resolve_annotations(namespace.get('__annotations__', {}), namespace.get('__module__', None))
|
||||
# annotation only fields need to come first in fields
|
||||
@@ -270,7 +275,7 @@ class ModelMetaclass(ABCMeta):
|
||||
value = namespace.get(ann_name, Undefined)
|
||||
allowed_types = get_args(ann_type) if get_origin(ann_type) is Union else (ann_type,)
|
||||
if (
|
||||
isinstance(value, ANNOTATED_FIELD_UNTOUCHED_TYPES)
|
||||
is_untouched(value)
|
||||
and ann_type != PyObject
|
||||
and not any(
|
||||
lenient_issubclass(get_origin(allowed_type), Type) for allowed_type in allowed_types
|
||||
@@ -289,7 +294,7 @@ class ModelMetaclass(ABCMeta):
|
||||
|
||||
untouched_types = UNTOUCHED_TYPES + config.keep_untouched
|
||||
for var_name, value in namespace.items():
|
||||
can_be_changed = var_name not in class_vars and not isinstance(value, untouched_types)
|
||||
can_be_changed = var_name not in class_vars and not is_untouched(value)
|
||||
if isinstance(value, ModelPrivateAttr):
|
||||
if not is_valid_private_name(var_name):
|
||||
raise NameError(
|
||||
|
||||
@@ -4,6 +4,7 @@ addopts = -p no:hypothesispytest
|
||||
filterwarnings =
|
||||
error
|
||||
ignore::DeprecationWarning:distutils
|
||||
ignore::DeprecationWarning:Cython
|
||||
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
|
||||
@@ -20,6 +20,11 @@ from pydantic import (
|
||||
)
|
||||
from pydantic.fields import Field, Schema
|
||||
|
||||
try:
|
||||
import cython
|
||||
except ImportError:
|
||||
cython = None
|
||||
|
||||
|
||||
def test_str_bytes():
|
||||
class Model(BaseModel):
|
||||
@@ -1745,3 +1750,26 @@ def test_default_factory_validator_child():
|
||||
pass
|
||||
|
||||
assert Child(foo=['a', 'b']).foo == ['a-1', 'b-1']
|
||||
|
||||
|
||||
@pytest.mark.skipif(cython is None, reason='cython not installed')
|
||||
def test_cython_function_untouched():
|
||||
Model = cython.inline(
|
||||
# language=Python
|
||||
"""
|
||||
from pydantic import BaseModel
|
||||
|
||||
class Model(BaseModel):
|
||||
a = 0.0
|
||||
b = 10
|
||||
|
||||
def get_double_a(self) -> float:
|
||||
return self.a + self.b
|
||||
|
||||
return Model
|
||||
"""
|
||||
)
|
||||
model = Model(a=10.2)
|
||||
assert model.a == 10.2
|
||||
assert model.b == 10
|
||||
return model.get_double_a() == 20.2
|
||||
|
||||
Reference in New Issue
Block a user