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

Add test for functoool.partial validators #5102

Closed
Closed
Show file tree
Hide file tree
Changes from 6 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
4 changes: 3 additions & 1 deletion pydantic/class_validators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import warnings
from collections import ChainMap
from functools import wraps
from functools import partial, partialmethod, wraps
from itertools import chain
from types import FunctionType
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Type, Union, overload
Expand Down Expand Up @@ -145,6 +145,8 @@ def _prepare_validator(function: AnyCallable, allow_reuse: bool) -> 'AnyClassMet
Avoid validators with duplicated names since without this, validators can be overwritten silently
which generally isn't the intended behaviour, don't run in ipython (see #312) or if allow_reuse is False.
"""
if isinstance(function, (partial, partialmethod)):
raise ConfigError('validators created using `functools` are not supported')
f_cls = function if isinstance(function, classmethod) else classmethod(function)
if not in_ipython() and not allow_reuse:
ref = f_cls.__func__.__module__ + '.' + f_cls.__func__.__qualname__
Expand Down
33 changes: 32 additions & 1 deletion tests/test_validators.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from collections import deque
from datetime import datetime
from enum import Enum
from functools import partial, partialmethod
from itertools import product
from typing import Dict, List, Optional, Tuple, Union
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

import pytest
from typing_extensions import Literal
Expand Down Expand Up @@ -1345,3 +1346,33 @@ class Model(BaseModel):
{'loc': ('foo',), 'msg': 'the list has duplicated items', 'type': 'value_error.list.unique_items'},
{'loc': ('bar',), 'msg': 'the list has duplicated items', 'type': 'value_error.list.unique_items'},
]


@pytest.mark.parametrize(
'func,allow_reuse',
[
pytest.param(partial, False, id='`partial` and check for reuse'),
pytest.param(partial, True, id='`partial` and ignore reuse'),
pytest.param(partialmethod, False, id='`partialmethod` and check for reuse'),
pytest.param(partialmethod, False, id='`partialmethod` and ignore reuse'),
JensHeinrich marked this conversation as resolved.
Show resolved Hide resolved
],
)
def test_functool_as_validator(
func: Callable,
allow_reuse: bool,
):
def custom_validator(
cls,
v: Any,
allowed: str,
) -> Any:
assert v == allowed, f'Only {allowed} allowed as value; given: {v}'
return v

validate = func(custom_validator, allowed='TEXT')

with pytest.raises(ConfigError, match='validators created using `functools` are not supported'):

class TestClass(BaseModel):
name: str
_custom_validate = validator('name', allow_reuse=allow_reuse)(validate)