0

Is there a way to patch a method used in a BeforeValidator of an Annotated type (used in Pydantic BaseSettings) such that the following code will work?

Why doesn't it work? Is it because Annotated type is constructed first and then the patching is executed, but the Annotated type is already in memory?

How could I refactor so it works? In the real code there is a Config class with some parsers and the asd_func tests if paths exist on disk, but in the test I would like to skip this particular validation.

from typing import Annotated
from unittest.mock import patch

from pydantic import BeforeValidator
from pydantic_settings import BaseSettings


def asd_func(value):
    return value


AsdType = Annotated[str, BeforeValidator(asd_func)]


class Config(BaseSettings):
    ASD: AsdType = "asd"


@patch(__name__ + ".asd_func", return_value="zzzzzz")
def test_config_load(_):
    config = Config()
    assert config.ASD == "zzzzzz"  # explodes here


test_config_load()
mrc
  • 126
  • 1
  • 11

1 Answers1

0

I've been thinking about how Annotated could've been created before mocking and came up with an idea to pack the asd_func inside another function. And it works :) they must be in the same file, however. Unfortunately using a lambda doesn't work, so it must be two functions... ugly. Full code:

from typing import Annotated
from unittest.mock import patch

from pydantic import BeforeValidator
from pydantic_settings import BaseSettings


def asd_func(value):
    return asd_func_internal(value)


def asd_func_internal(value):
    return value


AsdType = Annotated[str, BeforeValidator(asd_func)]


class Config(BaseSettings):
    ASD: AsdType = "asd"


def test_config_load():
    with patch(__name__ + ".asd_func_internal", return_value="zzzzzz"):
        config = Config()
        assert config.ASD == "zzzzzz"  # doesn't explode anymore


test_config_load()

mrc
  • 126
  • 1
  • 11