Pydantic: model.validate() should be private

Created on 13 May 2020  路  4Comments  路  Source: samuelcolvin/pydantic

Bug

Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":

             pydantic version: 1.3
            pydantic compiled: False
                 install path: C:\Python37\Lib\site-packages\pydantic
               python version: 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]
                     platform: Windows-8.1-6.3.9600-SP0
     optional deps. installed: ['email-validator']

Hi

I searched the docs, but could not find model.validate() function in the docs.
Pycharm showed me the function as an autocomplete suggestion
This is the first thing - not documented, but can be accessed

And I was happy to have that, and started to use.
Right after it turned out that it does not validate if the value is overwritten after init.

from pydantic import BaseModel
from uuid import UUID, uuid4

class A(BaseModel):
  text: str
  uid: UUID

a = A(text="hello", uid=uuid4())

print(a)

# no validation here
a.text=12
a.uid='Bela'

print(a)

print(A.validate(a))

print("nicely validated the bad thing")

print(A.validate(a.dict()))

After that I saw that there is a
class Config:
validate_assignment = True
possibility, but that is not the same...

I do not know which part is the bug, but it seems to me that something is wrong ;-)

BR,
George

bug

Most helpful comment

We found validate to be useful in the scenario below. If validate is made private, what would be the most "pydantic" way to validate extra fields?

import re
from pydantic import BaseModel, ConstrainedStr


class LanguageId(ConstrainedStr):
    """RFC 5646 language id. Example: en-US, nl, nl-BE, fr."""

    regex = re.compile("^[a-z]{2}(-[A-Z]{2})?$")


class MultiLanguageString(BaseModel):
    """A multi language string."""

    class Config:

        # Allow fields that are LanguageIds.
        extra = "allow"

    @root_validator
    def validate_language_ids(cls, values):
        """Validate all language ids."""
        for k, v in values.items():
            # Check that the keys are language ids, and the values are strings.
            LanguageId.validate(k)
            assert isinstance(v, str)
        return values

All 4 comments

_validate should be private, I'll change it in v2.

We found validate to be useful in the scenario below. If validate is made private, what would be the most "pydantic" way to validate extra fields?

import re
from pydantic import BaseModel, ConstrainedStr


class LanguageId(ConstrainedStr):
    """RFC 5646 language id. Example: en-US, nl, nl-BE, fr."""

    regex = re.compile("^[a-z]{2}(-[A-Z]{2})?$")


class MultiLanguageString(BaseModel):
    """A multi language string."""

    class Config:

        # Allow fields that are LanguageIds.
        extra = "allow"

    @root_validator
    def validate_language_ids(cls, values):
        """Validate all language ids."""
        for k, v in values.items():
            # Check that the keys are language ids, and the values are strings.
            LanguageId.validate(k)
            assert isinstance(v, str)
        return values

The validate method on ConstrainedStr is not what we're talking about here.

How custom types work in v2 might change, but that's a separate issue.

I attempted to create a root_validator with the method name being validate and it royally screwed me up for the better part of two days. So I am all for changing this please.

At the very least document the reserved public methods so that people don't accidentally call their validator methods this (i.e. dict, json, parse_obj, validate)

Was this page helpful?
0 / 5 - 0 ratings