'How to do exact one-to-one match validation with pydantic model schema?

How can I exactly match the Pydantic schema?

The suggested method is to attempt a dictionary conversion to the Pydantic model but that's not a one-one match.

I am using something similar for API response schema validation using pytest.

class Model_actual(BaseModel):
   val1 : str

dict_to_be_validated = {'val1':'Hello', 'val2':'World'}
   
assert Model_actual(**dict_to_be_validated) is not None

I am looking for this assertion to fail instead of pass because it this is not a one-to-one match.



Solution 1:[1]

By default, pydantic BaseModel's ignores extra fields (val2 in this case).

You can tell the model to forbid extra fields and raise a ValidationError by setting the BaseModel's Model Config extra option.

class Model_actual(BaseModel):
    val1: str

    class Config:
        extra = "forbid"

extra

whether to ignore, allow, or forbid extra attributes during model initialization. Accepts the string values of 'ignore', 'allow', or 'forbid', or values of the Extra enum (default: Extra.ignore). 'forbid' will cause validation to fail if extra attributes are included, 'ignore' will silently ignore any extra attributes, and 'allow' will assign the attributes to the model.

In [1]: from pydantic import BaseModel
   ...: 
   ...: class Model_actual(BaseModel):
   ...:     val1: str
   ...: 
   ...:     class Config:
   ...:         extra = "forbid"
   ...: 

In [2]: dict_to_be_validated = {"val1": "Hello", "val2": "World"}

In [3]: Model_actual(**dict_to_be_validated)
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 Model_actual(**dict_to_be_validated)

File ~/path/to/venv/lib/python3.9/site-packages/pydantic/main.py:331, in pydantic.main.BaseModel.__init__()

ValidationError: 1 validation error for Model_actual
val2
  extra fields not permitted (type=value_error.extra)

To catch that in a pytest test function, you let the test assert that an Exception is raised.

def test_model_ok():
    dict_to_be_validated = {"val1": "Hello"}

    obj = Model_actual(**dict_to_be_validated)
    assert obj.val1 == "Hello"

def test_model_ng():
    dict_to_be_validated = {"val1": "Hello", "val2": "World"}

    with pytest.raises(ValidationError) as exc:
        Model_actual(**dict_to_be_validated)

    assert exc.value.errors()[0]["msg"] == "extra fields not permitted"

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1