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

Fix issue not allowing validate_call decorator to be dynamically assigned to a class method. #8249

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions pydantic/_internal/_validate_call.py
Expand Up @@ -120,6 +120,11 @@ def __get__(self, obj: Any, objtype: type[Any] | None = None) -> ValidateCallWra
if obj is None:
try:
# Handle the case where a method is accessed as a class attribute
# Its possible this wrapper is dynamically applied to a class attribute not allowing
# name to be populated by __set_name__. In this case, we'll manually acquire the name
# from the function reference.
if self._name is None:
self._name = self.raw_function.__name__
jusexton marked this conversation as resolved.
Show resolved Hide resolved
return objtype.__getattribute__(objtype, self._name) # type: ignore
except AttributeError:
# This will happen the first time the attribute is accessed
Expand Down
12 changes: 12 additions & 0 deletions tests/test_validate_call.py
Expand Up @@ -684,6 +684,18 @@ def test(self, x: int):
assert bar.test('1') == (bar, 1)


def test_dynamic_method_decoration():
class Foo:
def bar(self, value: str) -> str:
return f'bar-{value}'

Foo.bar = validate_call(Foo.bar)
assert Foo.bar

foo = Foo()
assert foo.bar('test') == 'bar-test'


@pytest.mark.parametrize('decorator', [staticmethod, classmethod])
def test_classmethod_order_error(decorator):
name = decorator.__name__
Expand Down