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

Attribute error for functools.partial #5101

Closed
5 of 15 tasks
JensHeinrich opened this issue Feb 23, 2023 · 15 comments
Closed
5 of 15 tasks

Attribute error for functools.partial #5101

JensHeinrich opened this issue Feb 23, 2023 · 15 comments
Assignees
Labels
bug V1 Bug related to Pydantic V1.X

Comments

@JensHeinrich
Copy link

Initial Checks

  • I have searched GitHub for a duplicate issue and I'm sure this is something new
  • I have searched Google & StackOverflow for a solution and couldn't find anything
  • I have read and followed the docs and still think this is a bug
  • I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like FastAPI or mypy)

Description

Using a partialmethodor partial as a validator or root_validator creates an unhelpful AttributeError:

tests/conftest.py:14: in <module>
    class TestClass(BaseModel):
tests/conftest.py:17: in TestClass
    _custom_validate = validator("name")(validate)
pydantic/class_validators.py:93: in pydantic.class_validators.validator.dec
    ???
pydantic/class_validators.py:150: in pydantic.class_validators._prepare_validator
    ???
E   AttributeError: 'functools.partial' object has no attribute '__qualname__'

The problem is rooted at this code.

IMO an try except block with a test for partial methods would be useful here, telling the User to supply the "allow_reuse" parameter for partials.

Example Code

from functools import partial

from pydantic import validator, BaseModel
from pydantic.main import ModelMetaclass
from pydantic.utils import GetterDict

def custom_validator(additional_stuff: str, cls: ModelMetaclass, values: GetterDict):
    print(additional_stuff)
    return values

validate = partial(custom_validator, "TEXT")

class TestClass(BaseModel):
    name: str

    _custom_validate = validator("name")(validate)

Python, Pydantic & OS Version

pydantic version: 1.10.5
            pydantic compiled: True
                 install path: XXX/.venv/lib/python3.10/site-packages/pydantic
               python version: 3.10.7 (main, Nov 24 2022, 19:45:47) [GCC 12.2.0]
                     platform: Linux-5.19.0-31-generic-x86_64-with-glibc2.36
     optional deps. installed: ['typing-extensions']

Affected Components

@JensHeinrich JensHeinrich added bug V1 Bug related to Pydantic V1.X unconfirmed Bug not yet confirmed as valid/applicable labels Feb 23, 2023
@hramezani
Copy link
Member

Thanks @JensHeinrich for reporting this issue.

I can confirm the issue. partial() returns an instance, not a class or function.

it may fix by accessing the function in the following line. I mean replacing f_cls.__func__.__qualname__ with f_cls.__func__.func.__qualname__ in case of partial

ref = f'{f_cls.__func__.__module__}::{f_cls.__func__.__qualname__}'

Would you like to open a PR?

@hramezani hramezani removed the unconfirmed Bug not yet confirmed as valid/applicable label Feb 23, 2023
@JensHeinrich
Copy link
Author

I am already working on a PR, but at the moment I just add a better error

JensHeinrich pushed a commit to JensHeinrich/pydantic that referenced this issue Feb 24, 2023
This fixes pydantic#5101 atleast in regards to the unhelpful message
As this check is only done on creation of a class the overhead should be ok
@JensHeinrich
Copy link
Author

Even if the ref is created in a better way (or the check just skipped by using allow_reuse=True) another AttributeError is raised here

@JensHeinrich
Copy link
Author

JensHeinrich commented Feb 24, 2023

Also signature creation doesn't work on it

@hramezani
Copy link
Member

Even if the ref is created in a better way (or the check just skipped by using allow_reuse=True) another AttributeError is raised here

This one also can be fixed by the same change that I mentioned before.

I am already working on a PR, but at the moment I just add a better error

I think we can make it work at least on 1.10.x but I am not sure about V2.

@samuelcolvin Do you think we should prevent using functools.partial as a validator?

@JensHeinrich
Copy link
Author

TBH I feel functools is broken here and we are just adding a workaround.
Even a lambda gets an __qualname__

@samuelcolvin
Copy link
Member

TBH I feel functools is broken here and we are just adding a workaround. Even a lambda gets an __qualname__

agreed. Feel free to create an issue on cpython and copy me into it, I'd be interest to see what they say.

Also, can you create a PR against main to see if this is working there?

@hramezani
Copy link
Member

This one can be related https://bugs.python.org/issue34475

@JensHeinrich
Copy link
Author

I created an issue python/cpython#102323

@dmontagu
Copy link
Contributor

dmontagu commented Feb 28, 2023

I personally find the responses in the links from the last two comments reasonable; it seems we should just not assume that __qualname__ definitely exists.

@JensHeinrich
Copy link
Author

I'm good with using a default value instead, too.

@JensHeinrich
Copy link
Author

I am working on a PR for v1.10 already

@JensHeinrich
Copy link
Author

I would only allow those with reuse=True. Would you support that @samuelcolvin @dmontagu ?

JensHeinrich pushed a commit to JensHeinrich/pydantic that referenced this issue Mar 1, 2023
@dmontagu
Copy link
Contributor

dmontagu commented Mar 1, 2023

(responded on the PR; overall I am fine with the change)

dmontagu added a commit that referenced this issue Mar 8, 2023
* Use getattr and default for qualname

Was suggested in python/cpython#102323 by @sobolevn.
Fixes #5101
Superceedes #5102

* Import tests from #5102

* Fix signature generation for functools

* Use getattr and default for name

* Remove expectation of error from tests

* Reset tracked validators

* Describe changes

* Use getattr and default for module

* Use id as fallback

* Tweak name formatting

---------

Co-authored-by: JensHeinrich <github.com/JensHeinrich>
Co-authored-by: David Montague <35119617+dmontagu@users.noreply.github.com>
@dmontagu dmontagu assigned adriangb and Kludex and unassigned adriangb Apr 28, 2023
@Kludex
Copy link
Member

Kludex commented May 1, 2023

This was solved in #5362 for V2.

@Kludex Kludex closed this as completed May 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug V1 Bug related to Pydantic V1.X
Projects
None yet
Development

No branches or pull requests

6 participants