Fixes https://github.com/pydantic/pydantic/issues/7611

Long term I think a plan to allow pydantic-core to minimize the validation runtime cost of using referenced schemas (https://github.com/pydantic/pydantic-core/pull/989) makes the most sense, but this will do for now. We may even be able to add back some of the caching, but will have to be smarter about it.

This degrades the performance of [this schema building benchmark](https://github.com/pydantic/pydantic/blob/main/tests/benchmarks/test_fastapi_startup_generics.py) from `2.5s` to `3s` on my laptop.

Selected Reviewer: @dmontagu
Remove schema building caches. Fixes https://github.com/pydantic/pydantic/issues/7611

Long term I think a plan to allow pydantic-core to minimize the validation runtime cost of using referenced schemas (https://github.com/pydantic/pydantic-core/pull/989) makes the most sense, but this will do for now. We may even be able to add back some of the caching, but will have to be smarter about it.

This degrades the performance of [this schema building benchmark](https://github.com/pydantic/pydantic/blob/main/tests/benchmarks/test_fastapi_startup_generics.py) from `2.5s` to `3s` on my laptop.

Selected Reviewer: @dmontagu
import sys
from typing import Any, Type

if sys.version_info < (3, 9):
    from typing_extensions import Annotated
else:
    from typing import Annotated

import pytest

from pydantic import BaseModel, ConfigDict, Field, ValidationError


@pytest.fixture(scope='session', name='ModelWithStrictField')
def model_with_strict_field():
    class ModelWithStrictField(BaseModel):
        a: Annotated[int, Field(strict=True)]

    return ModelWithStrictField


@pytest.mark.parametrize(
    'value',
    [
        '1',
        True,
        1.0,
    ],
)
def test_parse_strict_mode_on_field_invalid(value: Any, ModelWithStrictField: Type[BaseModel]) -> None:
    with pytest.raises(ValidationError) as exc_info:
        ModelWithStrictField(a=value)
    assert exc_info.value.errors(include_url=False) == [
        {'type': 'int_type', 'loc': ('a',), 'msg': 'Input should be a valid integer', 'input': value}
    ]


def test_parse_strict_mode_on_field_valid(ModelWithStrictField: Type[BaseModel]) -> None:
    value = ModelWithStrictField(a=1)
    assert value.model_dump() == {'a': 1}


@pytest.fixture(scope='session', name='ModelWithStrictConfig')
def model_with_strict_config_false():
    class ModelWithStrictConfig(BaseModel):
        a: int
        # strict=False overrides the Config
        b: Annotated[int, Field(strict=False)]
        # strict=None or not including it is equivalent
        # lets this field be overridden by the Config
        c: Annotated[int, Field(strict=None)]
        d: Annotated[int, Field()]

        model_config = ConfigDict(strict=True)

    return ModelWithStrictConfig


def test_parse_model_with_strict_config_enabled(ModelWithStrictConfig: Type[BaseModel]) -> None:
    with pytest.raises(ValidationError) as exc_info:
        ModelWithStrictConfig(a='1', b=2, c=3, d=4)
    assert exc_info.value.errors(include_url=False) == [
        {'type': 'int_type', 'loc': ('a',), 'msg': 'Input should be a valid integer', 'input': '1'}
    ]
    with pytest.raises(ValidationError) as exc_info:
        ModelWithStrictConfig(a=1, b=2, c='3', d=4)
    assert exc_info.value.errors(include_url=False) == [
        {'type': 'int_type', 'loc': ('c',), 'msg': 'Input should be a valid integer', 'input': '3'}
    ]
    with pytest.raises(ValidationError) as exc_info:
        ModelWithStrictConfig(a=1, b=2, c=3, d='4')
    assert exc_info.value.errors(include_url=False) == [
        {'type': 'int_type', 'loc': ('d',), 'msg': 'Input should be a valid integer', 'input': '4'}
    ]
    values = [
        ModelWithStrictConfig(a=1, b='2', c=3, d=4),
        ModelWithStrictConfig(a=1, b=2, c=3, d=4),
    ]
    assert all(v.model_dump() == {'a': 1, 'b': 2, 'c': 3, 'd': 4} for v in values)


def test_parse_model_with_strict_config_disabled(ModelWithStrictConfig: Type[BaseModel]) -> None:
    class Model(ModelWithStrictConfig):
        model_config = ConfigDict(strict=False)

    values = [
        Model(a='1', b=2, c=3, d=4),
        Model(a=1, b=2, c='3', d=4),
        Model(a=1, b=2, c=3, d='4'),
        Model(a=1, b='2', c=3, d=4),
        Model(a=1, b=2, c=3, d=4),
    ]
    assert all(v.model_dump() == {'a': 1, 'b': 2, 'c': 3, 'd': 4} for v in values)

import sys
from typing import Any, Type

if sys.version_info < (3, 9):
    from typing_extensions import Annotated
else:
    from typing import Annotated

import pytest

from pydantic import BaseModel, ConfigDict, Field, ValidationError


@pytest.fixture(scope='session', name='ModelWithStrictField')
def model_with_strict_field():
    class ModelWithStrictField(BaseModel):
        a: Annotated[int, Field(strict=True)]

    return ModelWithStrictField


@pytest.mark.parametrize(
    'value',
    [
        '1',
        True,
        1.0,
    ],
)
def test_parse_strict_mode_on_field_invalid(value: Any, ModelWithStrictField: Type[BaseModel]) -> None:
    with pytest.raises(ValidationError) as exc_info:
        ModelWithStrictField(a=value)
    assert exc_info.value.errors(include_url=False) == [
        {'type': 'int_type', 'loc': ('a',), 'msg': 'Input should be a valid integer', 'input': value}
    ]


def test_parse_strict_mode_on_field_valid(ModelWithStrictField: Type[BaseModel]) -> None:
    value = ModelWithStrictField(a=1)
    assert value.model_dump() == {'a': 1}


@pytest.fixture(scope='session', name='ModelWithStrictConfig')
def model_with_strict_config_false():
    class ModelWithStrictConfig(BaseModel):
        a: int
        # strict=False overrides the Config
        b: Annotated[int, Field(strict=False)]
        # strict=None or not including it is equivalent
        # lets this field be overridden by the Config
        c: Annotated[int, Field(strict=None)]
        d: Annotated[int, Field()]

        model_config = ConfigDict(strict=True)

    return ModelWithStrictConfig


def test_parse_model_with_strict_config_enabled(ModelWithStrictConfig: Type[BaseModel]) -> None:
    with pytest.raises(ValidationError) as exc_info:
        ModelWithStrictConfig(a='1', b=2, c=3, d=4)
    assert exc_info.value.errors(include_url=False) == [
        {'type': 'int_type', 'loc': ('a',), 'msg': 'Input should be a valid integer', 'input': '1'}
    ]
    with pytest.raises(ValidationError) as exc_info:
        ModelWithStrictConfig(a=1, b=2, c='3', d=4)
    assert exc_info.value.errors(include_url=False) == [
        {'type': 'int_type', 'loc': ('c',), 'msg': 'Input should be a valid integer', 'input': '3'}
    ]
    with pytest.raises(ValidationError) as exc_info:
        ModelWithStrictConfig(a=1, b=2, c=3, d='4')
    assert exc_info.value.errors(include_url=False) == [
        {'type': 'int_type', 'loc': ('d',), 'msg': 'Input should be a valid integer', 'input': '4'}
    ]
    values = [
        ModelWithStrictConfig(a=1, b='2', c=3, d=4),
        ModelWithStrictConfig(a=1, b=2, c=3, d=4),
    ]
    assert all(v.model_dump() == {'a': 1, 'b': 2, 'c': 3, 'd': 4} for v in values)


def test_parse_model_with_strict_config_disabled(ModelWithStrictConfig: Type[BaseModel]) -> None:
    class Model(ModelWithStrictConfig):
        model_config = ConfigDict(strict=False)

    values = [
        Model(a='1', b=2, c=3, d=4),
        Model(a=1, b=2, c='3', d=4),
        Model(a=1, b=2, c=3, d='4'),
        Model(a=1, b='2', c=3, d=4),
        Model(a=1, b=2, c=3, d=4),
    ]
    assert all(v.model_dump() == {'a': 1, 'b': 2, 'c': 3, 'd': 4} for v in values)
