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

Pydantics model validator causing weird issues when in classmethod-decorators #13617

Open
ollz272 opened this issue Oct 3, 2024 · 2 comments

Comments

@ollz272
Copy link

ollz272 commented Oct 3, 2024

We have the following in our ruff config:

[tool.ruff.lint.pep8-naming]
classmethod-decorators = ["classmethod", "pydantic.model_validator", "pydantic.field_validator"]

This is so we can do the following in our code:

import pydantic
from pydantic import BaseModel

class Model(BaseModel):
    """Some Model."""

    foo: str
    bar: int

    @pydantic.model_validator(mode="before")
    def some_validation(cls, data):
        """Before Validation."""
        if data["foo"] == "hello" and data["bar"] == 1:
            raise ValueError

        return data

This works well, however when we set the validator mode to "after", this is an instance method rather than a class method, so we get:

import pydantic
from pydantic import BaseModel


class Model(BaseModel):
    """Some Model."""

    foo: str
    bar: int

    @pydantic.model_validator(mode="before")
    def before_validation(cls, data):
        """Before Validation."""
        if data["foo"] == "hello" and data["bar"] == 1:
            raise ValueError

        return data

    @pydantic.model_validator(mode="after")
    def after_validation(self):
        """After Validation."""
        if not self.bar:
            raise ValueError

        return self

We get the following:

 N804 First argument of a class method should be named `cls`
   |
19 |     @pydantic.model_validator(mode="after")
20 |     def after_validation(self):
   |                          ^^^^ N804
21 |         """After Validation."""
22 |         if not self.bar:
   |
   = help: Rename `self` to `cls`

Which is slightly... annoying. We know we can remove this from config and add a class method decorator, but this has always felt a bit verbose to use.

Is there a better way to handle this case? is this something ruff would consider fixing?

@zanieb
Copy link
Member

zanieb commented Oct 3, 2024

How would you imagine us fixing this? Taking the full invocation in the config?

classmethod-decorators = ["classmethod", "pydantic.model_validator(mode=\"before\")", "pydantic.field_validator"]

@dhruvmanila
Copy link
Member

FWIW, the Pydantic docs do recommend to add the @classmethod decorator:

The first argument should be cls (and we also recommend you use @classmethod below @model_validator for proper type checking), [...]

https://docs.pydantic.dev/latest/concepts/validators/#field-validators

And, similarly for field validators:

A few things to note on validators:

  1. @field_validators are "class methods", so the first argument value they receive is the UserModel class, not an instance of UserModel. We recommend you use the @classmethod decorator on them below the @field_validator decorator to get proper type checking.

https://docs.pydantic.dev/latest/concepts/validators/#field-validators

Do you use any type checker like mypy or Pyright? Do they work properly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants