From 88c4e704d02064d027667433b2356f8b8148d62300614c970a8f84de30db3fd8 Mon Sep 17 00:00:00 2001 From: Steve Kowalik Date: Thu, 30 May 2024 04:57:46 +0000 Subject: [PATCH] - Add patch support-pytest-8.patch: * Support changes in pytest 8.x. OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-pydantic?expand=0&rev=51 --- python-pydantic.changes | 6 + python-pydantic.spec | 2 + support-pytest-8.patch | 382 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 390 insertions(+) create mode 100644 support-pytest-8.patch diff --git a/python-pydantic.changes b/python-pydantic.changes index e56182f..f0ff705 100644 --- a/python-pydantic.changes +++ b/python-pydantic.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu May 30 04:56:19 UTC 2024 - Steve Kowalik + +- Add patch support-pytest-8.patch: + * Support changes in pytest 8.x. + ------------------------------------------------------------------- Sat Apr 27 07:45:31 UTC 2024 - Dirk Müller diff --git a/python-pydantic.spec b/python-pydantic.spec index f427ddd..ce31626 100644 --- a/python-pydantic.spec +++ b/python-pydantic.spec @@ -33,6 +33,8 @@ Summary: Data validation and settings management using python type hintin License: MIT URL: https://github.com/pydantic/pydantic Source: https://github.com/pydantic/pydantic/archive/v%{version}.tar.gz#/pydantic-%{version}.tar.gz +# PATCH-FIX-UPSTREAM gh#pydantic/pydantic#9527 +Patch0: support-pytest-8.patch BuildRequires: %{python_module hatch-fancy-pypi-readme} BuildRequires: %{python_module hatchling} BuildRequires: %{python_module packaging} diff --git a/support-pytest-8.patch b/support-pytest-8.patch new file mode 100644 index 0000000..cb06b40 --- /dev/null +++ b/support-pytest-8.patch @@ -0,0 +1,382 @@ +From 7fb31529124f51cceb32d1d7b8ae9b58c0606b17 Mon Sep 17 00:00:00 2001 +From: Steve Kowalik +Date: Thu, 30 May 2024 14:14:04 +1000 +Subject: [PATCH] Ignore other warnings when checking warnings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Building on Michał's amazing work in PR#9040, extend the pattern to also +ignore other warnings that are emitted by pytest.warns() when running +under Pytest 8.x. This also continues to support Pytest 7.x. + +Co-authored-by: Michał Górny + +Fixes: #9025 +--- + tests/conftest.py | 2 +- + tests/test_config.py | 84 +++++++++++--------- + tests/test_deprecated.py | 156 ++++++++++++++++++++++---------------- + tests/test_json_schema.py | 9 ++- + tests/test_validators.py | 1 + + 5 files changed, 146 insertions(+), 106 deletions(-) + +diff --git a/tests/conftest.py b/tests/conftest.py +index e0c0dee018..421afade2e 100644 +--- a/tests/conftest.py ++++ b/tests/conftest.py +@@ -49,7 +49,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 +diff --git a/tests/test_config.py b/tests/test_config.py +index 1a5e31628a..31b2320326 100644 +--- a/tests/test_config.py ++++ b/tests/test_config.py +@@ -1,6 +1,7 @@ + import json + import re + import sys ++import warnings + from contextlib import nullcontext as does_not_raise + from decimal import Decimal + from inspect import signature +@@ -349,45 +350,54 @@ class Model(BaseModel): + assert m == m.model_copy() + + def test_config_class_is_deprecated(self): +- with pytest.warns( +- PydanticDeprecatedSince20, match='Support for class-based `config` is deprecated, use ConfigDict instead.' +- ): +- +- class Config(BaseConfig): +- pass ++ 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( ++ PydanticDeprecatedSince20, ++ match='Support for class-based `config` is deprecated, use ConfigDict instead.', ++ ): ++ ++ class Config(BaseConfig): ++ pass + + def test_config_class_attributes_are_deprecated(self): +- with pytest.warns( +- PydanticDeprecatedSince20, +- match='Support for class-based `config` is deprecated, use ConfigDict instead.', +- ): +- assert BaseConfig.validate_assignment is False +- +- with pytest.warns( +- PydanticDeprecatedSince20, +- match='Support for class-based `config` is deprecated, use ConfigDict instead.', +- ): +- assert BaseConfig().validate_assignment is False +- +- with pytest.warns( +- PydanticDeprecatedSince20, +- match='Support for class-based `config` is deprecated, use ConfigDict instead.', +- ): +- +- class Config(BaseConfig): +- pass +- +- with pytest.warns( +- PydanticDeprecatedSince20, +- match='Support for class-based `config` is deprecated, use ConfigDict instead.', +- ): +- assert Config.validate_assignment is False +- +- with pytest.warns( +- PydanticDeprecatedSince20, +- match='Support for class-based `config` is deprecated, use ConfigDict instead.', +- ): +- assert Config().validate_assignment is False ++ 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( ++ PydanticDeprecatedSince20, ++ match='Support for class-based `config` is deprecated, use ConfigDict instead.', ++ ): ++ assert BaseConfig.validate_assignment is False ++ ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='Support for class-based `config` is deprecated, use ConfigDict instead.', ++ ): ++ assert BaseConfig().validate_assignment is False ++ ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='Support for class-based `config` is deprecated, use ConfigDict instead.', ++ ): ++ ++ class Config(BaseConfig): ++ pass ++ ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='Support for class-based `config` is deprecated, use ConfigDict instead.', ++ ): ++ assert Config.validate_assignment is False ++ ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='Support for class-based `config` is deprecated, use ConfigDict instead.', ++ ): ++ assert Config().validate_assignment is False + + @pytest.mark.filterwarnings('ignore:.* is deprecated.*:DeprecationWarning') + def test_config_class_missing_attributes(self): +diff --git a/tests/test_deprecated.py b/tests/test_deprecated.py +index fda6879597..2e58e8b433 100644 +--- a/tests/test_deprecated.py ++++ b/tests/test_deprecated.py +@@ -1,5 +1,6 @@ + import platform + import re ++import warnings + from datetime import date, timedelta + from pathlib import Path + from types import SimpleNamespace +@@ -273,8 +274,12 @@ class Model(BaseModel): + x: int + y: int + +- with pytest.warns(PydanticDeprecatedSince20, match='The `parse_raw` method is deprecated'): +- model = Model.parse_raw('{"x": 1, "y": 2}') ++ 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(PydanticDeprecatedSince20, match='The `parse_raw` method is deprecated'): ++ model = Model.parse_raw('{"x": 1, "y": 2}') + assert model.model_dump() == {'x': 1, 'y': 2} + + +@@ -284,9 +289,13 @@ class Model(BaseModel): + x: int + y: int + +- with pytest.warns(PydanticDeprecatedSince20, match='The `parse_raw` method is deprecated'): +- with pytest.raises(ValidationError, match='1 validation error for Model') as exc_info: +- Model.parse_raw('invalid') ++ 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(PydanticDeprecatedSince20, match='The `parse_raw` method is deprecated'): ++ with pytest.raises(ValidationError, match='1 validation error for Model') as exc_info: ++ Model.parse_raw('invalid') + + # insert_assert(exc_info.value.errors(include_url=False)) + assert exc_info.value.errors(include_url=False) == [ +@@ -435,10 +444,14 @@ class Model(BaseModel): + + def test_field_include_deprecation(): + m = '`include` is deprecated and does nothing. It will be removed, use `exclude` instead' +- with pytest.warns(PydanticDeprecatedSince20, match=m): ++ 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(PydanticDeprecatedSince20, match=m): + +- class Model(BaseModel): +- x: int = Field(include=True) ++ class Model(BaseModel): ++ x: int = Field(include=True) + + + def test_unique_items_items(): +@@ -664,10 +677,14 @@ def test_parse_obj(): + def test_parse_file(tmp_path): + path = tmp_path / 'test.json' + path.write_text('{"x": 12}') +- with pytest.warns( +- PydanticDeprecatedSince20, match='^The `parse_file` method is deprecated; load the data from file,' +- ): +- assert SimpleModel.parse_file(str(path)).model_dump() == {'x': 12} ++ 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( ++ PydanticDeprecatedSince20, match='^The `parse_file` method is deprecated; load the data from file,' ++ ): ++ assert SimpleModel.parse_file(str(path)).model_dump() == {'x': 12} + + + def test_construct(): +@@ -736,61 +753,68 @@ def test_deprecated_module(tmp_path: Path) -> None: + class Model(BaseModel): + x: int + +- assert hasattr(parse_obj_as, '__deprecated__') +- with pytest.warns( +- PydanticDeprecatedSince20, +- match='`parse_obj_as` is deprecated. Use `pydantic.TypeAdapter.validate_python` instead.', +- ): +- parse_obj_as(Model, {'x': 1}) +- +- assert hasattr(schema_json_of, '__deprecated__') +- with pytest.warns( +- PydanticDeprecatedSince20, +- match='`schema_json_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', +- ): +- schema_json_of(Model) +- +- assert hasattr(schema_of, '__deprecated__') +- with pytest.warns( +- PydanticDeprecatedSince20, match='`schema_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.' +- ): +- schema_of(Model) +- +- assert hasattr(load_str_bytes, '__deprecated__') +- with pytest.warns(PydanticDeprecatedSince20, match='`load_str_bytes` is deprecated.'): +- load_str_bytes('{"x": 1}') +- +- assert hasattr(load_file, '__deprecated__') +- file = tmp_path / 'main.py' +- file.write_text('{"x": 1}') +- with pytest.warns(PydanticDeprecatedSince20, match='`load_file` is deprecated.'): +- load_file(file) +- +- assert hasattr(pydantic_encoder, '__deprecated__') +- with pytest.warns( +- PydanticDeprecatedSince20, +- match='`pydantic_encoder` is deprecated, use `pydantic_core.to_jsonable_python` instead.', +- ): +- pydantic_encoder(Model(x=1)) +- +- assert hasattr(custom_pydantic_encoder, '__deprecated__') +- with pytest.warns( +- PydanticDeprecatedSince20, match='`custom_pydantic_encoder` is deprecated, use `BaseModel.model_dump` instead.' +- ): +- custom_pydantic_encoder({int: lambda x: str(x)}, Model(x=1)) +- +- assert hasattr(timedelta_isoformat, '__deprecated__') +- with pytest.warns(PydanticDeprecatedSince20, match='`timedelta_isoformat` is deprecated.'): +- timedelta_isoformat(timedelta(seconds=1)) +- +- with pytest.warns( +- PydanticDeprecatedSince20, match='The `validate_arguments` method is deprecated; use `validate_call` instead.' +- ): +- +- def test(a: int, b: int): +- pass ++ 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') ++ assert hasattr(parse_obj_as, '__deprecated__') ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='`parse_obj_as` is deprecated. Use `pydantic.TypeAdapter.validate_python` instead.', ++ ): ++ parse_obj_as(Model, {'x': 1}) ++ ++ assert hasattr(schema_json_of, '__deprecated__') ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='`schema_json_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', ++ ): ++ schema_json_of(Model) ++ ++ assert hasattr(schema_of, '__deprecated__') ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='`schema_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', ++ ): ++ schema_of(Model) ++ ++ assert hasattr(load_str_bytes, '__deprecated__') ++ with pytest.warns(PydanticDeprecatedSince20, match='`load_str_bytes` is deprecated.'): ++ load_str_bytes('{"x": 1}') ++ ++ assert hasattr(load_file, '__deprecated__') ++ file = tmp_path / 'main.py' ++ file.write_text('{"x": 1}') ++ with pytest.warns(PydanticDeprecatedSince20, match='`load_file` is deprecated.'): ++ load_file(file) ++ ++ assert hasattr(pydantic_encoder, '__deprecated__') ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='`pydantic_encoder` is deprecated, use `pydantic_core.to_jsonable_python` instead.', ++ ): ++ pydantic_encoder(Model(x=1)) ++ ++ assert hasattr(custom_pydantic_encoder, '__deprecated__') ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='`custom_pydantic_encoder` is deprecated, use `BaseModel.model_dump` instead.', ++ ): ++ custom_pydantic_encoder({int: lambda x: str(x)}, Model(x=1)) ++ ++ assert hasattr(timedelta_isoformat, '__deprecated__') ++ with pytest.warns(PydanticDeprecatedSince20, match='`timedelta_isoformat` is deprecated.'): ++ timedelta_isoformat(timedelta(seconds=1)) ++ ++ with pytest.warns( ++ PydanticDeprecatedSince20, ++ match='The `validate_arguments` method is deprecated; use `validate_call` instead.', ++ ): ++ ++ def test(a: int, b: int): ++ pass + +- validate_arguments()(test) ++ validate_arguments()(test) + + + def test_deprecated_color(): +diff --git a/tests/test_json_schema.py b/tests/test_json_schema.py +index e6c60557a5..85d833c15c 100644 +--- a/tests/test_json_schema.py ++++ b/tests/test_json_schema.py +@@ -5,6 +5,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 +@@ -1385,8 +1386,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', +diff --git a/tests/test_validators.py b/tests/test_validators.py +index 52a8bda88f..b286c49b1b 100644 +--- a/tests/test_validators.py ++++ b/tests/test_validators.py +@@ -2554,6 +2554,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'): +