From 5d1ab9ea41eabc8fa2e52147dacf2fae161d2bba Mon Sep 17 00:00:00 2001 From: K900 Date: Tue, 13 Jun 2023 00:44:59 +0300 Subject: [PATCH 1/7] Fix racy doctests (#6103) --- docs/build/exec_examples.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/build/exec_examples.py b/docs/build/exec_examples.py index 648a6268045..b17f3906d72 100755 --- a/docs/build/exec_examples.py +++ b/docs/build/exec_examples.py @@ -353,6 +353,9 @@ def error(*desc: str) -> None: if upgrade: versions.extend(populate_upgraded_versions(file, file_text, lowest_version)) + # flush importlib caches to ensure the code we just generated is discovered + importlib.invalidate_caches() + json_outputs: set[str | None] = set() should_run_as_is = not requirements final_content: list[str] = [] From b386008d95513a27beabfeaba1eaa5854c4528cd Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Tue, 13 Jun 2023 20:10:55 +0200 Subject: [PATCH 2/7] =?UTF-8?q?=E2=9C=85=20Update=20FastAPI=20test=20scrip?= =?UTF-8?q?t=20(#6117)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changes/6117-Kludex.md | 1 + tests/test_fastapi.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changes/6117-Kludex.md diff --git a/changes/6117-Kludex.md b/changes/6117-Kludex.md new file mode 100644 index 00000000000..73dcd74c2e7 --- /dev/null +++ b/changes/6117-Kludex.md @@ -0,0 +1 @@ +Update install method of FastAPI for internal tests in CI. diff --git a/tests/test_fastapi.sh b/tests/test_fastapi.sh index 26fcc2174e4..25373f35ae1 100755 --- a/tests/test_fastapi.sh +++ b/tests/test_fastapi.sh @@ -9,6 +9,6 @@ latest_tag_commit=$(git rev-list --tags --max-count=1) latest_tag=$(git describe --tags "${latest_tag_commit}") git checkout "${latest_tag}" -pip install .[all,dev,doc,test] +pip install -r requirements.txt ./scripts/test.sh From ccedd746de49179fe835610f793459b84fb9f754 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 14 Jun 2023 13:16:53 +0100 Subject: [PATCH 3/7] add roadmap to announcement (#6120) --- docs/favicon.png | Bin 891 -> 594 bytes docs/logo-white.svg | 6 ++++-- docs/theme/announce.html | 5 ++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/favicon.png b/docs/favicon.png index c5ea1d13da1a3ff497d42727a93a097f1a7b4e8e..dac6c4765ca8a5bb1905e83120355a43317c82e6 100644 GIT binary patch literal 594 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEdf3uu0Z;^YRbT(na?x)fbP&P z3GxeO`02{=`rYS!CfxcvO85`w+laGnt2n+gN#p7L>wT?FIsUSH3WFXKoxphK|w590IJzMYp|9j2g$}6s@ty_ctaC~u3+ZCKx zuY3B}8h%&9nm_gIZ|vR%7Bx(NU%K_+!-n3fY&zM*e6%a+$!X>SiM4!4a{ULT^C8=bc5)W*Je87~K~ z#*Hl|`6u<;qbI$QT9F%-KYwqW%;Ktjw~O!X-j^=%{L_;SZ63D~^0}Hp>8Z1-XI}chbI<2rY$A6Q Vo6icy$pIsU!PC{xWt~$(696Q74le)z literal 891 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKptm- zM`SUOx&gwB#~18e3lwB8@$_|Nf6T=$sLC~Op|BPM1LHGK7sn8f<8!atXH0gKIR4T9 z9uHqx#$2r}8m>APA|W!abAn`KTAFrA#gv>`<<0%**$O|tveFIS-8*)gc6%FWIC-Hn+{qQj(?qtybi=C%bng=U&>=wM#&iSJdGOenakf3Svo z{x-cEh3N-=bT0qLan09UruEsrYfsq@Y?iy7EyODEapl}ulU1!gKA0?+mQ$MYy`nSE z=7!PXInC>sU+G`$W@mqi_IRMM?OBA z`HnNNGkn>tc=Np-j~sOaOC@5DR4)3LD?e6k-@;;MySZ4a=J@BuRW55*{3~1i_j_Z#y6Dwo zrEm4t%)guAxBI@TfbQ$ww@=oT?LEuuKj-M-ZQIvri0A9@&VG@Z+b(wZ+d9thGqYc? z`Q@!U*w`~`QmXvl7rERdP`( zkYX@0FtpS)G|)9L4>2^iGB&p|G|)CMvNAB(nA-zNln4#E`6-!cmAEw=Ffcg`)F276 zAviy+q&%@Gm7%=6TrV>(yEr+qAXP8FD1G)j8!4co@T!oAlAy$Lg@U5|w9K4Tg_6pG zRE5lfl4J&kiaC!z@o*G|X=t4CKYhmYX%GXmGPhnbx3IFX_hb=fVFi~4lfx;@%9}$J qPT#n4;>ejJGDp}?H+U@Y(qnifE?Dx($#g2v3I - + + diff --git a/docs/theme/announce.html b/docs/theme/announce.html index 74289e8ce15..f19ef09c8d0 100644 --- a/docs/theme/announce.html +++ b/docs/theme/announce.html @@ -1,4 +1,3 @@ - + -Pydantic V2 alpha 1 is here: -We're releasing the first alpha of Pydantic V2 for evaluation. Read the alpha release blog post for details. +Pydantic's commercial roadmap is out 🚀, and we'd love to hear your feedback 📢! From d7afe9936e8cbd20d2f5b6f5576e2ca9f14c5642 Mon Sep 17 00:00:00 2001 From: Markus Scheidgen Date: Tue, 20 Jun 2023 14:04:24 +0200 Subject: [PATCH 4/7] Fixed literal validator errors for unhashable values (#6194) --- changes/6188-markus1978.md | 1 + pydantic/validators.py | 2 +- tests/test_validators.py | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 changes/6188-markus1978.md diff --git a/changes/6188-markus1978.md b/changes/6188-markus1978.md new file mode 100644 index 00000000000..2a092decec0 --- /dev/null +++ b/changes/6188-markus1978.md @@ -0,0 +1 @@ +Fixed literal validator errors for unhashable values. \ No newline at end of file diff --git a/pydantic/validators.py b/pydantic/validators.py index fb6d0418831..549a235e0c3 100644 --- a/pydantic/validators.py +++ b/pydantic/validators.py @@ -488,7 +488,7 @@ def make_literal_validator(type_: Any) -> Callable[[Any], Any]: def literal_validator(v: Any) -> Any: try: return allowed_choices[v] - except KeyError: + except (KeyError, TypeError): raise errors.WrongConstantError(given=v, permitted=permitted_choices) return literal_validator diff --git a/tests/test_validators.py b/tests/test_validators.py index 5c4d57eac62..5af82373596 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -1189,6 +1189,24 @@ class Model(BaseModel): ] +def test_literal_validator_non_str_value(): + class Model(BaseModel): + a: Literal['foo'] + + Model(a='foo') + + with pytest.raises(ValidationError) as exc_info: + Model(a={'bar': 'foo'}) + assert exc_info.value.errors() == [ + { + 'loc': ('a',), + 'msg': "unexpected value; permitted: 'foo'", + 'type': 'value_error.const', + 'ctx': {'given': {'bar': 'foo'}, 'permitted': ('foo',)}, + } + ] + + def test_literal_validator_str_enum(): class Bar(str, Enum): FIZ = 'fiz' From 51b4751b1d594e7e6c48b13c6be06df15181c6e4 Mon Sep 17 00:00:00 2001 From: mark-todd <60781787+mark-todd@users.noreply.github.com> Date: Fri, 23 Jun 2023 17:06:59 +0100 Subject: [PATCH 5/7] Bug fix for forward refs in generics (#6157) --- changes/6130-mark-todd.md | 1 + pydantic/generics.py | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 changes/6130-mark-todd.md diff --git a/changes/6130-mark-todd.md b/changes/6130-mark-todd.md new file mode 100644 index 00000000000..bb27325aa72 --- /dev/null +++ b/changes/6130-mark-todd.md @@ -0,0 +1 @@ +Fixed bug with generics receiving forward refs diff --git a/pydantic/generics.py b/pydantic/generics.py index 5dcda6df320..a75b6b987da 100644 --- a/pydantic/generics.py +++ b/pydantic/generics.py @@ -6,6 +6,7 @@ Any, ClassVar, Dict, + ForwardRef, Generic, Iterator, List, @@ -19,7 +20,7 @@ ) from weakref import WeakKeyDictionary, WeakValueDictionary -from typing_extensions import Annotated +from typing_extensions import Annotated, Literal as ExtLiteral from .class_validators import gather_all_validators from .fields import DeferredType @@ -30,6 +31,8 @@ if sys.version_info >= (3, 10): from typing import _UnionGenericAlias +if sys.version_info >= (3, 8): + from typing import Literal GenericModelT = TypeVar('GenericModelT', bound='GenericModel') TypeVarType = Any # since mypy doesn't allow the use of TypeVar as a type @@ -267,6 +270,8 @@ def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any: annotated_type, *annotations = type_args return Annotated[replace_types(annotated_type, type_map), tuple(annotations)] + if (origin_type is ExtLiteral) or (sys.version_info >= (3, 8) and origin_type is Literal): + return type_map.get(type_, type_) # Having type args is a good indicator that this is a typing module # class instantiation or a generic alias of some sort. if type_args: @@ -317,7 +322,12 @@ def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any: # If all else fails, we try to resolve the type directly and otherwise just # return the input with no modifications. - return type_map.get(type_, type_) + new_type = type_map.get(type_, type_) + # Convert string to ForwardRef + if isinstance(new_type, str): + return ForwardRef(new_type) + else: + return new_type def check_parameters_count(cls: Type[GenericModel], parameters: Tuple[Any, ...]) -> None: From 19e2eb9021321e23b36606e57588d306e341c17f Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Mon, 26 Jun 2023 16:22:20 +0330 Subject: [PATCH 6/7] Add Pydantic `Json` field support to settings management (#6250) --- changes/6250-hramezani.md | 1 + pydantic/env_settings.py | 6 +++++- tests/test_settings.py | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 changes/6250-hramezani.md diff --git a/changes/6250-hramezani.md b/changes/6250-hramezani.md new file mode 100644 index 00000000000..243d2c83801 --- /dev/null +++ b/changes/6250-hramezani.md @@ -0,0 +1 @@ +Add Pydantic `Json` field support to settings management. diff --git a/pydantic/env_settings.py b/pydantic/env_settings.py index e9c070620f6..6c446e51c6a 100644 --- a/pydantic/env_settings.py +++ b/pydantic/env_settings.py @@ -6,8 +6,9 @@ from .config import BaseConfig, Extra from .fields import ModelField from .main import BaseModel +from .types import JsonWrapper from .typing import StrPath, display_as_type, get_origin, is_union -from .utils import deep_update, path_type, sequence_like +from .utils import deep_update, lenient_issubclass, path_type, sequence_like env_file_sentinel = str(object()) @@ -231,6 +232,9 @@ def field_is_complex(self, field: ModelField) -> Tuple[bool, bool]: """ Find out if a field is complex, and if so whether JSON errors should be ignored """ + if lenient_issubclass(field.annotation, JsonWrapper): + return False, False + if field.is_complex(): allow_parse_failure = False elif is_union(get_origin(field.type_)) and field.sub_fields and any(f.is_complex() for f in field.sub_fields): diff --git a/tests/test_settings.py b/tests/test_settings.py index d61e6209bc3..6440ced13c2 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -7,7 +7,7 @@ import pytest -from pydantic import BaseModel, BaseSettings, Field, HttpUrl, NoneStr, SecretStr, ValidationError, dataclasses +from pydantic import BaseModel, BaseSettings, Field, HttpUrl, Json, NoneStr, SecretStr, ValidationError, dataclasses from pydantic.env_settings import ( EnvSettingsSource, InitSettingsSource, @@ -1278,3 +1278,35 @@ def parse_env_var(cls, field_name: str, raw_val: str): s = Settings() assert s.top == {1: 'apple', 2: 'banana'} + + +def test_env_json_field(env): + class Settings(BaseSettings): + x: Json + + env.set('x', '{"foo": "bar"}') + + s = Settings() + assert s.x == {'foo': 'bar'} + + env.set('x', 'test') + with pytest.raises(ValidationError) as exc_info: + Settings() + assert exc_info.value.errors() == [{'loc': ('x',), 'msg': 'Invalid JSON', 'type': 'value_error.json'}] + + +def test_env_json_field_dict(env): + class Settings(BaseSettings): + x: Json[Dict[str, int]] + + env.set('x', '{"foo": 1}') + + s = Settings() + assert s.x == {'foo': 1} + + env.set('x', '{"foo": "bar"}') + with pytest.raises(ValidationError) as exc_info: + Settings() + assert exc_info.value.errors() == [ + {'loc': ('x', 'foo'), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'} + ] From 0e8a387d6752dd859676da53298601ccae6a23a7 Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Fri, 30 Jun 2023 13:48:15 +0330 Subject: [PATCH 7/7] Prepare for 1.10.10 (#6308) --- HISTORY.md | 13 +++++++++++++ changes/6117-Kludex.md | 1 - changes/6130-mark-todd.md | 1 - changes/6188-markus1978.md | 1 - changes/6250-hramezani.md | 1 - pydantic/version.py | 2 +- 6 files changed, 14 insertions(+), 5 deletions(-) delete mode 100644 changes/6117-Kludex.md delete mode 100644 changes/6130-mark-todd.md delete mode 100644 changes/6188-markus1978.md delete mode 100644 changes/6250-hramezani.md diff --git a/HISTORY.md b/HISTORY.md index 14d0eb314ba..b129569a4f7 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,9 @@ +## v2.0b3 (2023-06-16) + +Third beta pre-release of Pydantic V2 + +See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0b3) + ## v2.0b2 (2023-06-03) Add `from_attributes` runtime flag to `TypeAdapter.validate_python` and `BaseModel.model_validate`. @@ -34,6 +40,13 @@ First pre-release of Pydantic V2! See [this post](https://docs.pydantic.dev/blog/pydantic-v2-alpha/) for more details. +## v1.10.10 (2023-06-30) + +* Add Pydantic `Json` field support to settings management, #6250 by @hramezani +* Fixed literal validator errors for unhashable values, #6188 by @markus1978 +* Fixed bug with generics receiving forward refs, #6130 by @mark-todd +* Update install method of FastAPI for internal tests in CI, #6117 by @Kludex + ## v1.10.9 (2023-06-07) * Fix trailing zeros not ignored in Decimal validation, #5968 by @hramezani diff --git a/changes/6117-Kludex.md b/changes/6117-Kludex.md deleted file mode 100644 index 73dcd74c2e7..00000000000 --- a/changes/6117-Kludex.md +++ /dev/null @@ -1 +0,0 @@ -Update install method of FastAPI for internal tests in CI. diff --git a/changes/6130-mark-todd.md b/changes/6130-mark-todd.md deleted file mode 100644 index bb27325aa72..00000000000 --- a/changes/6130-mark-todd.md +++ /dev/null @@ -1 +0,0 @@ -Fixed bug with generics receiving forward refs diff --git a/changes/6188-markus1978.md b/changes/6188-markus1978.md deleted file mode 100644 index 2a092decec0..00000000000 --- a/changes/6188-markus1978.md +++ /dev/null @@ -1 +0,0 @@ -Fixed literal validator errors for unhashable values. \ No newline at end of file diff --git a/changes/6250-hramezani.md b/changes/6250-hramezani.md deleted file mode 100644 index 243d2c83801..00000000000 --- a/changes/6250-hramezani.md +++ /dev/null @@ -1 +0,0 @@ -Add Pydantic `Json` field support to settings management. diff --git a/pydantic/version.py b/pydantic/version.py index c0fceba50e5..b7114b49d9c 100644 --- a/pydantic/version.py +++ b/pydantic/version.py @@ -1,6 +1,6 @@ __all__ = 'compiled', 'VERSION', 'version_info' -VERSION = '1.10.9' +VERSION = '1.10.10' try: import cython # type: ignore