ensure cythonized functions are left untouched2 (#2228)

* ensure cythonized functions are left untouched2

* add change
This commit is contained in:
Samuel Colvin
2021-02-13 15:48:55 +00:00
committed by GitHub
parent 78934db631
commit b87e2492cc
4 changed files with 37 additions and 2 deletions
+1
View File
@@ -0,0 +1 @@
ensure cythonized functions are left untouched when creating models, based on #1944 by @kollmats
+7 -2
View File
@@ -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(
+1
View File
@@ -4,6 +4,7 @@ addopts = -p no:hypothesispytest
filterwarnings =
error
ignore::DeprecationWarning:distutils
ignore::DeprecationWarning:Cython
[flake8]
max-line-length = 120
+28
View File
@@ -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