From 4179708ab8cde073df6171d77e9edd1707f230c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 18 Mar 2024 15:19:06 +0100 Subject: [PATCH 1/4] Ignore irrelevant warnings triggered by tests to fix pytest-8 Add irrelevant warnings triggered by different parts of tests to ignored warning list when using `pytest.warns()`, in order to fix compatibility with pytest-8. In previous versions of pytest, the call to `pytest.warns()` would consume all warnings, including these not matched by the clause. Starting with pytest-8, remaining warnings are reemitted and therefore trigger errors. To preserve compatibility with both pytest versions, just ignore them rather than asserting for both. --- tests/test_validators.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_validators.py b/tests/test_validators.py index c2039a19b8..9eb08399d3 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -2551,6 +2551,7 @@ class Model(BaseModel): assert Model(x=1, y=2).model_dump() == {'x': 2, 'y': 3} +@pytest.mark.filterwarnings('ignore:Pydantic V1 style `@root_validator` validators are deprecated.*:pydantic.warnings.PydanticDeprecatedSince20') def test_root_validator_allow_reuse_same_field(): with pytest.warns(UserWarning, match='`root_val` overrides an existing Pydantic `@root_validator` decorator'): From 810a3726289fdf1cf397ffc12424092ccd6cf99a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 18 Mar 2024 15:29:52 +0100 Subject: [PATCH 2/4] Replace deprecated PYDANTIC_ERRORS_OMIT_URL in conftest Replace the deprecated `PYDANTIC_ERRORS_OMIT_URL` with `PYDANTIC_ERRORS_INCLUDE_URL` in `tests/conftest.py`, to fix deprecation warning from pydantic-core. This warning was incidentally ignored by pytest-7 but it is now triggered by pytest-8. --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index c5dcce2523..cd1ed73cc6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -47,7 +47,7 @@ def _create_module_file(code, tmp_path, name): def disable_error_urls(): # Don't add URLs during docs tests when printing # Otherwise we'll get version numbers in the URLs that will update frequently - os.environ['PYDANTIC_ERRORS_OMIT_URL'] = 'true' + os.environ['PYDANTIC_ERRORS_INCLUDE_URL'] = 'false' @pytest.fixture From 14974903663058051541e42e1c4e682395c9d873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 18 Mar 2024 15:33:18 +0100 Subject: [PATCH 3/4] Modify parse_raw() and parse_file() not to emit spurious warnings Modify the `parse_raw()` and `parse_file()` to ignore deprecation warnings from their implementation details. The methods themselves are deprecated, and that should be the only deprecation warning interesting to the user. This also fixes test failures with pytest-8 that no longer ignores warnings that did not match `pytest.warns()`. --- pydantic/main.py | 78 +++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/pydantic/main.py b/pydantic/main.py index e12f238242..2b979e84d4 100644 --- a/pydantic/main.py +++ b/pydantic/main.py @@ -1105,35 +1105,37 @@ def parse_raw( # noqa: D102 ) from .deprecated import parse - try: - obj = parse.load_str_bytes( - b, - proto=proto, - content_type=content_type, - encoding=encoding, - allow_pickle=allow_pickle, - ) - except (ValueError, TypeError) as exc: - import json - - # try to match V1 - if isinstance(exc, UnicodeDecodeError): - type_str = 'value_error.unicodedecode' - elif isinstance(exc, json.JSONDecodeError): - type_str = 'value_error.jsondecode' - elif isinstance(exc, ValueError): - type_str = 'value_error' - else: - type_str = 'type_error' - - # ctx is missing here, but since we've added `input` to the error, we're not pretending it's the same - error: pydantic_core.InitErrorDetails = { - # The type: ignore on the next line is to ignore the requirement of LiteralString - 'type': pydantic_core.PydanticCustomError(type_str, str(exc)), # type: ignore - 'loc': ('__root__',), - 'input': b, - } - raise pydantic_core.ValidationError.from_exception_data(cls.__name__, [error]) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + try: + obj = parse.load_str_bytes( + b, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + ) + except (ValueError, TypeError) as exc: + import json + + # try to match V1 + if isinstance(exc, UnicodeDecodeError): + type_str = 'value_error.unicodedecode' + elif isinstance(exc, json.JSONDecodeError): + type_str = 'value_error.jsondecode' + elif isinstance(exc, ValueError): + type_str = 'value_error' + else: + type_str = 'type_error' + + # ctx is missing here, but since we've added `input` to the error, we're not pretending it's the same + error: pydantic_core.InitErrorDetails = { + # The type: ignore on the next line is to ignore the requirement of LiteralString + 'type': pydantic_core.PydanticCustomError(type_str, str(exc)), # type: ignore + 'loc': ('__root__',), + 'input': b, + } + raise pydantic_core.ValidationError.from_exception_data(cls.__name__, [error]) return cls.model_validate(obj) @classmethod @@ -1158,14 +1160,16 @@ def parse_file( # noqa: D102 ) from .deprecated import parse - obj = parse.load_file( - path, - proto=proto, - content_type=content_type, - encoding=encoding, - allow_pickle=allow_pickle, - ) - return cls.parse_obj(obj) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + obj = parse.load_file( + path, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + ) + return cls.parse_obj(obj) @classmethod @typing_extensions.deprecated( From 748e90e216a23f7d0d4145e3eaf1b1b180be7bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 18 Mar 2024 16:50:38 +0100 Subject: [PATCH 4/4] Fix test_json_schema double warning failure with pytest-8 Add a warning filter to test_json_schema to resolve the test failure with pytest-8. The test currently uses parametrization to assert for a single call emitting two separate warnings, since `pytest.warns()` used to consume all non-matched warnings before. However, with pytest-8 it reemits the remaining warnings and therefore causes test to fail due to the `error` filter. When pydantic requires pytest >= 8, we can instead switch to using two `pytest.warns()`. --- tests/test_json_schema.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_json_schema.py b/tests/test_json_schema.py index 730c73bc05..b8ba09eeec 100644 --- a/tests/test_json_schema.py +++ b/tests/test_json_schema.py @@ -3,6 +3,7 @@ import re import sys import typing +import warnings from datetime import date, datetime, time, timedelta from decimal import Decimal from enum import Enum, IntEnum @@ -1382,8 +1383,12 @@ class Model(BaseModel): class MyGenerator(GenerateJsonSchema): ignored_warning_kinds = () - with pytest.warns(PydanticJsonSchemaWarning, match=warning_match): - model_schema = Model.model_json_schema(schema_generator=MyGenerator) + with warnings.catch_warnings(): + # we need to explicitly ignore the other warning in pytest-8 + # TODO: rewrite it to use two nested pytest.warns() when pytest-7 is no longer supported + warnings.simplefilter("ignore") + with pytest.warns(PydanticJsonSchemaWarning, match=warning_match): + model_schema = Model.model_json_schema(schema_generator=MyGenerator) assert model_schema == { 'properties': {'callback': {'title': 'Callback', 'type': 'integer'}}, 'title': 'Model',