From 2980a8875859647340af93d2e3b26be056aa77b210929686fa8c67c44119aa28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=C3=A9ta=20Machov=C3=A1?= Date: Fri, 8 Jan 2021 13:36:08 +0000 Subject: [PATCH] Accepting request 861663 from home:mcalabkova:branches:devel:languages:python Staging:I - Update to 1.7.3 * python 3.9 support * Private model attributes * "secrets files" support in BaseSettings * convert stdlib dataclasses to pydantic dataclasses and use stdlib dataclasses in models * few bugfixes - Drop validate-config.patch OBS-URL: https://build.opensuse.org/request/show/861663 OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-pydantic?expand=0&rev=16 --- pydantic-1.6.1.tar.gz | 3 - pydantic-1.7.3.tar.gz | 3 + python-pydantic.changes | 11 ++ python-pydantic.spec | 14 +- validate-config.patch | 304 ---------------------------------------- 5 files changed, 21 insertions(+), 314 deletions(-) delete mode 100644 pydantic-1.6.1.tar.gz create mode 100644 pydantic-1.7.3.tar.gz delete mode 100644 validate-config.patch diff --git a/pydantic-1.6.1.tar.gz b/pydantic-1.6.1.tar.gz deleted file mode 100644 index df3c03d..0000000 --- a/pydantic-1.6.1.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:41f71147910f26944770cdcac90131241d36fd8212b34468d043e871da065e20 -size 244677 diff --git a/pydantic-1.7.3.tar.gz b/pydantic-1.7.3.tar.gz new file mode 100644 index 0000000..298d837 --- /dev/null +++ b/pydantic-1.7.3.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fef39e969d69cc73af8c98728c27e719ccb38b16a52ef2e69a088540731f1fa +size 266702 diff --git a/python-pydantic.changes b/python-pydantic.changes index 9dff0f1..cb810d5 100644 --- a/python-pydantic.changes +++ b/python-pydantic.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Fri Jan 8 13:10:40 UTC 2021 - Markéta Machová + +- Update to 1.7.3 + * python 3.9 support + * Private model attributes + * "secrets files" support in BaseSettings + * convert stdlib dataclasses to pydantic dataclasses and use stdlib dataclasses in models + * few bugfixes +- Drop validate-config.patch + ------------------------------------------------------------------- Mon Dec 7 01:00:22 UTC 2020 - Benjamin Greiner diff --git a/python-pydantic.spec b/python-pydantic.spec index e037d6d..2155900 100644 --- a/python-pydantic.spec +++ b/python-pydantic.spec @@ -1,7 +1,7 @@ # # spec file for package python-pydantic # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # Copyright (c) 2019, Martin Hauke # # All modifications and additions to the file contributed by third parties @@ -20,24 +20,23 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-pydantic -Version: 1.6.1 +Version: 1.7.3 Release: 0 Summary: Data validation and settings management using python type hinting License: MIT Group: Development/Languages/Python URL: https://github.com/samuelcolvin/pydantic Source: https://github.com/samuelcolvin/pydantic/archive/v%{version}.tar.gz#/pydantic-%{version}.tar.gz -# PATCH-FIX-UPSTREAM https://github.com/samuelcolvin/pydantic/commit/9c4860ce964a4eb2e22eedc21f21d406c596a82f Valdiate arguments config (#1663) -Patch0: validate-config.patch BuildRequires: %{python_module email_validator >= 1.0.3} +BuildRequires: %{python_module pytest-mock} BuildRequires: %{python_module pytest} BuildRequires: %{python_module python-dotenv >= 0.10.4} BuildRequires: %{python_module setuptools} BuildRequires: %{python_module typing_extensions >= 3.7.2} -BuildRequires: (python36-dataclasses if python36-base) -BuildRequires: (python3-dataclasses if python3-base < 3.7) BuildRequires: fdupes BuildRequires: python-rpm-macros +BuildRequires: (python3-dataclasses if python3-base < 3.7) +BuildRequires: (python36-dataclasses if python36-base) %if 0%{?python_version_nodots} == 36 Requires: python-dataclasses %endif @@ -52,7 +51,8 @@ Data validation and settings management using Python type hinting. %prep %setup -q -n pydantic-%{version} -%patch0 -p1 +# compatibility with new pytest +sed -i 's/yield_fixture/fixture/' tests/conftest.py %build %python_build diff --git a/validate-config.patch b/validate-config.patch deleted file mode 100644 index 52982f2..0000000 --- a/validate-config.patch +++ /dev/null @@ -1,304 +0,0 @@ -From 9c4860ce964a4eb2e22eedc21f21d406c596a82f Mon Sep 17 00:00:00 2001 -From: Samuel Colvin -Date: Sun, 6 Sep 2020 23:17:52 +0100 -Subject: [PATCH] Valdiate arguments config (#1663) - -* add `configs` to validate_arguments - -* simplify `validate_arguments` and add annotation for parameter `configs` - -* change double quotes to single quotes - -* reformat code - -* fix mypy error - -* fix mypy 'maximum semantic analysis' error - -* rename 'configs' > 'config_params' - -* change name and usage, start tests - -* prevent setting fields on custom config - -* add docs and fix mypy - -* tweak docs - -* add change - -Co-authored-by: quantpy ---- - changes/1663-samuelcolvin.md | 1 + - docs/examples/validation_decorator_config.py | 26 +++++++++ - docs/usage/validation_decorator.md | 21 +++++++- - pydantic/decorator.py | 51 +++++++++++++----- - setup.cfg | 1 - - tests/test_decorator.py | 55 ++++++++++++++++++++ - 6 files changed, 138 insertions(+), 17 deletions(-) - create mode 100644 changes/1663-samuelcolvin.md - create mode 100644 docs/examples/validation_decorator_config.py - -Index: pydantic-1.6.1/changes/1663-samuelcolvin.md -=================================================================== ---- /dev/null -+++ pydantic-1.6.1/changes/1663-samuelcolvin.md -@@ -0,0 +1 @@ -+add `config` to `@validate_arguments` -Index: pydantic-1.6.1/docs/examples/validation_decorator_config.py -=================================================================== ---- /dev/null -+++ pydantic-1.6.1/docs/examples/validation_decorator_config.py -@@ -0,0 +1,26 @@ -+from pydantic import ValidationError, validate_arguments -+ -+ -+class Foobar: -+ def __init__(self, v: str): -+ self.v = v -+ -+ def __add__(self, other: 'Foobar') -> str: -+ return f'{self} + {other}' -+ -+ def __str__(self) -> str: -+ return f'Foobar({self.v})' -+ -+ -+@validate_arguments(config=dict(arbitrary_types_allowed=True)) -+def add_foobars(a: Foobar, b: Foobar): -+ return a + b -+ -+ -+c = add_foobars(Foobar('a'), Foobar('b')) -+print(c) -+ -+try: -+ add_foobars(1, 2) -+except ValidationError as e: -+ print(e) -Index: pydantic-1.6.1/docs/usage/validation_decorator.md -=================================================================== ---- pydantic-1.6.1.orig/docs/usage/validation_decorator.md -+++ pydantic-1.6.1/docs/usage/validation_decorator.md -@@ -78,8 +78,23 @@ _(This script is complete, it should run - ```py - {!.tmp_examples/validation_decorator_async.py!} - ``` --_(This script is complete, it should run "as is")_ - -+## Custom Config -+ -+The model behind `validate_arguments` can be customised using a config setting which is equivalent to -+setting the `Config` sub-class in normal models. -+ -+!!! warning -+ The `fields` and `alias_generator` properties of `Config` which allow aliases to be configured are not supported -+ yet with `@validate_arguments`, using them will raise an error. -+ -+Configuration is set using the `config` keyword argument to the decorator, it may be either a config class -+or a dict of properties which are converted to a class later. -+ -+```py -+{!.tmp_examples/validation_decorator_config.py!} -+``` -+_(This script is complete, it should run "as is")_ - - ## Limitations - -@@ -126,7 +141,9 @@ in future. - - ### Config and Validators - --Custom [`Config`](model_config.md) and [validators](validators.md) are not yet supported. -+`fields` and `alias_generator` on custom [`Config`](model_config.md) are not supported, see [above](#custom-config). -+ -+Neither are [validators](validators.md). - - ### Model fields and reserved arguments - -Index: pydantic-1.6.1/pydantic/decorator.py -=================================================================== ---- pydantic-1.6.1.orig/pydantic/decorator.py -+++ pydantic-1.6.1/pydantic/decorator.py -@@ -1,5 +1,5 @@ - from functools import wraps --from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Tuple, TypeVar, cast, get_type_hints -+from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Tuple, Type, TypeVar, Union, cast, get_type_hints - - from . import validator - from .errors import ConfigError -@@ -12,22 +12,30 @@ if TYPE_CHECKING: - from .typing import AnyCallable - - Callable = TypeVar('Callable', bound=AnyCallable) -+ ConfigType = Union[None, Type[Any], Dict[str, Any]] - - --def validate_arguments(function: 'Callable') -> 'Callable': -+def validate_arguments(func: 'Callable' = None, *, config: 'ConfigType' = None) -> 'Callable': - """ - Decorator to validate the arguments passed to a function. - """ -- vd = ValidatedFunction(function) - -- @wraps(function) -- def wrapper_function(*args: Any, **kwargs: Any) -> Any: -- return vd.call(*args, **kwargs) -- -- wrapper_function.vd = vd # type: ignore -- wrapper_function.raw_function = vd.raw_function # type: ignore -- wrapper_function.model = vd.model # type: ignore -- return cast('Callable', wrapper_function) -+ def validate(_func: 'Callable') -> 'Callable': -+ vd = ValidatedFunction(_func, config) -+ -+ @wraps(_func) -+ def wrapper_function(*args: Any, **kwargs: Any) -> Any: -+ return vd.call(*args, **kwargs) -+ -+ wrapper_function.vd = vd # type: ignore -+ wrapper_function.raw_function = vd.raw_function # type: ignore -+ wrapper_function.model = vd.model # type: ignore -+ return cast('Callable', wrapper_function) -+ -+ if func: -+ return validate(func) -+ else: -+ return cast('Callable', validate) - - - ALT_V_ARGS = 'v__args' -@@ -36,7 +44,7 @@ V_POSITIONAL_ONLY_NAME = 'v__positional_ - - - class ValidatedFunction: -- def __init__(self, function: 'Callable'): -+ def __init__(self, function: 'Callable', config: 'ConfigType'): # noqa C901 - from inspect import signature, Parameter - - parameters: Mapping[str, Parameter] = signature(function).parameters -@@ -100,7 +108,7 @@ class ValidatedFunction: - # same with kwargs - fields[self.v_kwargs_name] = Dict[Any, Any], None - -- self.create_model(fields, takes_args, takes_kwargs) -+ self.create_model(fields, takes_args, takes_kwargs, config) - - def call(self, *args: Any, **kwargs: Any) -> Any: - values = self.build_values(args, kwargs) -@@ -170,9 +178,24 @@ class ValidatedFunction: - else: - return self.raw_function(**d) - -- def create_model(self, fields: Dict[str, Any], takes_args: bool, takes_kwargs: bool) -> None: -+ def create_model(self, fields: Dict[str, Any], takes_args: bool, takes_kwargs: bool, config: 'ConfigType') -> None: - pos_args = len(self.arg_mapping) - -+ class CustomConfig: -+ pass -+ -+ if not TYPE_CHECKING: # pragma: no branch -+ if isinstance(config, dict): -+ CustomConfig = type('Config', (), config) # noqa: F811 -+ elif config is not None: -+ CustomConfig = config # noqa: F811 -+ -+ if hasattr(CustomConfig, 'fields') or hasattr(CustomConfig, 'alias_generator'): -+ raise ConfigError( -+ 'Setting the "fields" and "alias_generator" property on custom Config for ' -+ '@validate_arguments is not yet supported, please remove.' -+ ) -+ - class DecoratorBaseModel(BaseModel): - @validator(self.v_args_name, check_fields=False, allow_reuse=True) - def check_args(cls, v: List[Any]) -> List[Any]: -@@ -196,7 +219,7 @@ class ValidatedFunction: - keys = ', '.join(map(repr, v)) - raise TypeError(f'positional-only argument{plural} passed as keyword argument{plural}: {keys}') - -- class Config: -+ class Config(CustomConfig): - extra = Extra.forbid - - self.model = create_model(to_camel(self.raw_function.__name__), __base__=DecoratorBaseModel, **fields) -Index: pydantic-1.6.1/setup.cfg -=================================================================== ---- pydantic-1.6.1.orig/setup.cfg -+++ pydantic-1.6.1/setup.cfg -@@ -1,6 +1,5 @@ - [tool:pytest] - testpaths = tests --timeout = 10 - filterwarnings = - error - ignore::DeprecationWarning:distutils -Index: pydantic-1.6.1/tests/test_decorator.py -=================================================================== ---- pydantic-1.6.1.orig/tests/test_decorator.py -+++ pydantic-1.6.1/tests/test_decorator.py -@@ -70,6 +70,7 @@ def test_wrap(): - assert issubclass(foo_bar.model, BaseModel) - assert foo_bar.model.__fields__.keys() == {'a', 'b', 'args', 'kwargs'} - assert foo_bar.model.__name__ == 'FooBar' -+ assert foo_bar.model.schema()['title'] == 'FooBar' - # signature is slightly different on 3.6 - if sys.version_info >= (3, 7): - assert repr(inspect.signature(foo_bar)) == '' -@@ -262,3 +263,57 @@ def test_class_method(): - {'loc': ('a',), 'msg': 'field required', 'type': 'value_error.missing'}, - {'loc': ('b',), 'msg': 'field required', 'type': 'value_error.missing'}, - ] -+ -+ -+def test_config_title(): -+ @validate_arguments(config=dict(title='Testing')) -+ def foo(a: int, b: int): -+ return f'{a}, {b}' -+ -+ assert foo(1, 2) == '1, 2' -+ assert foo(1, b=2) == '1, 2' -+ assert foo.model.schema()['title'] == 'Testing' -+ -+ -+def test_config_title_cls(): -+ class Config: -+ title = 'Testing' -+ -+ @validate_arguments(config=Config) -+ def foo(a: int, b: int): -+ return f'{a}, {b}' -+ -+ assert foo(1, 2) == '1, 2' -+ assert foo(1, b=2) == '1, 2' -+ assert foo.model.schema()['title'] == 'Testing' -+ -+ -+def test_config_fields(): -+ with pytest.raises(ConfigError, match='Setting the "fields" and "alias_generator" property on custom Config for @'): -+ -+ @validate_arguments(config=dict(fields={'b': 'bang'})) -+ def foo(a: int, b: int): -+ return f'{a}, {b}' -+ -+ -+def test_config_arbitrary_types_allowed(): -+ class EggBox: -+ def __str__(self) -> str: -+ return 'EggBox()' -+ -+ @validate_arguments(config=dict(arbitrary_types_allowed=True)) -+ def foo(a: int, b: EggBox): -+ return f'{a}, {b}' -+ -+ assert foo(1, EggBox()) == '1, EggBox()' -+ with pytest.raises(ValidationError) as exc_info: -+ assert foo(1, 2) == '1, 2' -+ -+ assert exc_info.value.errors() == [ -+ { -+ 'loc': ('b',), -+ 'msg': 'instance of EggBox expected', -+ 'type': 'type_error.arbitrary_type', -+ 'ctx': {'expected_arbitrary_type': 'EggBox'}, -+ }, -+ ]