From 70dcb069ff20bbab3942f123b32fc35205af2f19 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Fri, 24 Mar 2023 15:22:14 +0000 Subject: [PATCH] use `pytest-examples` (#465) * use pytest-examples * fix docstring tests on emscripten * working on linting examples * fixing more examples * update docstring * updating examples * all examples formatted * reformat examples * uprev deps * revert coverage * revert other uprevs * remove "HYPOTHESIS_PROFILE: slow" * fix ci * linting and add tmate * move tmate * add -g to RUSTFLAGS * allow coverage to fail --- .github/workflows/ci.yml | 6 +- Makefile | 4 +- README.md | 49 ++++---- pydantic_core/core_schema.py | 166 ++++++++++++++++++++------- tests/benchmarks/complete_schema.py | 2 +- tests/requirements-linting.txt | 4 +- tests/requirements.txt | 3 +- tests/test_docstrings.py | 127 ++++++-------------- tests/test_errors.py | 1 - tests/test_misc.py | 10 -- tests/validators/test_dataclasses.py | 1 - tests/validators/test_model_init.py | 1 - 12 files changed, 194 insertions(+), 180 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cde6abc9c7..44b8477c02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: name: cache rust uses: Swatinem/rust-cache@v2 with: - key: coverage-v1 + key: coverage-v2 - run: cargo install rustfilt coverage-prepare if: steps.cache-rust.outputs.cache-hit != 'true' @@ -47,9 +47,6 @@ jobs: - run: pip freeze - run: coverage run -m pytest - env: - BENCHMARK_VS_PYDANTIC: 1 - HYPOTHESIS_PROFILE: slow - run: ls -lha - run: coverage xml @@ -262,6 +259,7 @@ jobs: uses: re-actors/alls-green@release/v1 with: jobs: ${{ toJSON(needs) }} + allowed-failures: coverage build: name: build on ${{ matrix.platform || matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }}) diff --git a/Makefile b/Makefile index 6732667aab..31db676617 100644 --- a/Makefile +++ b/Makefile @@ -89,9 +89,11 @@ rust-benchmark: cargo rust-bench .PHONY: testcov -testcov: build-coverage test +testcov: build-coverage @rm -rf htmlcov @mkdir -p htmlcov + coverage run -m pytest + coverage report coverage html -d htmlcov/python coverage-prepare html pydantic_core/*.so diff --git a/README.md b/README.md index 9bcecbeb50..5f4aef07f5 100644 --- a/README.md +++ b/README.md @@ -25,32 +25,35 @@ Example of usage: ```py from pydantic_core import SchemaValidator, ValidationError -v = SchemaValidator({ - 'type': 'typed-dict', - 'fields': { - 'name': { - 'type': 'typed-dict-field', - 'schema': { - 'type': 'str', + +v = SchemaValidator( + { + 'type': 'typed-dict', + 'fields': { + 'name': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'str', + }, }, - }, - 'age': { - 'type': 'typed-dict-field', - 'schema': { - 'type': 'int', - 'ge': 18, + 'age': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'int', + 'ge': 18, + }, + }, + 'is_developer': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'default', + 'schema': {'type': 'bool'}, + 'default': True, + }, }, }, - 'is_developer': { - 'type': 'typed-dict-field', - 'schema': { - 'type': 'default', - 'schema': {'type': 'bool'}, - 'default': True, - } - }, - }, -}) + } +) r1 = v.validate_python({'name': 'Samuel', 'age': 35}) assert r1 == {'name': 'Samuel', 'age': 35, 'is_developer': True} diff --git a/pydantic_core/core_schema.py b/pydantic_core/core_schema.py index b6728d1e7a..4bd535f621 100644 --- a/pydantic_core/core_schema.py +++ b/pydantic_core/core_schema.py @@ -464,6 +464,7 @@ def any_schema(*, ref: str | None = None, metadata: Any = None, serialization: S ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.any_schema() v = SchemaValidator(schema) assert v.validate_python(1) == 1 @@ -490,6 +491,7 @@ def none_schema(*, ref: str | None = None, metadata: Any = None, serialization: ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.none_schema() v = SchemaValidator(schema) assert v.validate_python(None) is None @@ -519,6 +521,7 @@ def bool_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.bool_schema() v = SchemaValidator(schema) assert v.validate_python('True') is True @@ -563,6 +566,7 @@ def int_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.int_schema(multiple_of=2, le=6, ge=2) v = SchemaValidator(schema) assert v.validate_python('4') == 4 @@ -625,6 +629,7 @@ def float_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.float_schema(le=0.8, ge=0.2) v = SchemaValidator(schema) assert v.validate_python('0.5') == 0.5 @@ -689,6 +694,7 @@ def str_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.str_schema(max_length=10, min_length=2) v = SchemaValidator(schema) assert v.validate_python('hello') == 'hello' @@ -745,6 +751,7 @@ def bytes_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.bytes_schema(max_length=10, min_length=2) v = SchemaValidator(schema) assert v.validate_python(b'hello') == b'hello' @@ -804,6 +811,7 @@ def date_schema( ```py from datetime import date from pydantic_core import SchemaValidator, core_schema + schema = core_schema.date_schema(le=date(2020, 1, 1), ge=date(2019, 1, 1)) v = SchemaValidator(schema) assert v.validate_python(date(2019, 6, 1)) == date(2019, 6, 1) @@ -865,6 +873,7 @@ def time_schema( ```py from datetime import time from pydantic_core import SchemaValidator, core_schema + schema = core_schema.time_schema(le=time(12, 0, 0), ge=time(6, 0, 0)) v = SchemaValidator(schema) assert v.validate_python(time(9, 0, 0)) == time(9, 0, 0) @@ -922,6 +931,7 @@ def datetime_schema( ```py from datetime import datetime from pydantic_core import SchemaValidator, core_schema + schema = core_schema.datetime_schema() v = SchemaValidator(schema) now = datetime.now() @@ -986,6 +996,7 @@ def timedelta_schema( ```py from datetime import timedelta from pydantic_core import SchemaValidator, core_schema + schema = core_schema.timedelta_schema(le=timedelta(days=1), ge=timedelta(days=0)) v = SchemaValidator(schema) assert v.validate_python(timedelta(hours=12)) == timedelta(hours=12) @@ -1030,7 +1041,8 @@ def literal_schema( ```py from pydantic_core import SchemaValidator, core_schema - schema = core_schema.literal_schema('hello', "world") + + schema = core_schema.literal_schema('hello', 'world') v = SchemaValidator(schema) assert v.validate_python('hello') == 'hello' ``` @@ -1168,6 +1180,7 @@ def callable_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.callable_schema() v = SchemaValidator(schema) v.validate_python(min) @@ -1222,6 +1235,7 @@ def list_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.list_schema(core_schema.int_schema(), min_length=0, max_length=10) v = SchemaValidator(schema) assert v.validate_python(['4']) == [4] @@ -1273,7 +1287,10 @@ def tuple_positional_schema( ```py from pydantic_core import SchemaValidator, core_schema - schema = core_schema.tuple_positional_schema(core_schema.int_schema(), core_schema.str_schema()) + + schema = core_schema.tuple_positional_schema( + core_schema.int_schema(), core_schema.str_schema() + ) v = SchemaValidator(schema) assert v.validate_python((1, 'hello')) == (1, 'hello') ``` @@ -1326,7 +1343,10 @@ def tuple_variable_schema( ```py from pydantic_core import SchemaValidator, core_schema - schema = core_schema.tuple_variable_schema(items_schema=core_schema.int_schema(), min_length=0, max_length=10) + + schema = core_schema.tuple_variable_schema( + items_schema=core_schema.int_schema(), min_length=0, max_length=10 + ) v = SchemaValidator(schema) assert v.validate_python(('1', 2, 3)) == (1, 2, 3) ``` @@ -1380,7 +1400,10 @@ def set_schema( ```py from pydantic_core import SchemaValidator, core_schema - schema = core_schema.set_schema(items_schema=core_schema.int_schema(), min_length=0, max_length=10) + + schema = core_schema.set_schema( + items_schema=core_schema.int_schema(), min_length=0, max_length=10 + ) v = SchemaValidator(schema) assert v.validate_python({1, '2', 3}) == {1, 2, 3} ``` @@ -1438,7 +1461,10 @@ def frozenset_schema( ```py from pydantic_core import SchemaValidator, core_schema - schema = core_schema.frozenset_schema(items_schema=core_schema.int_schema(), min_length=0, max_length=10) + + schema = core_schema.frozenset_schema( + items_schema=core_schema.int_schema(), min_length=0, max_length=10 + ) v = SchemaValidator(schema) assert v.validate_python(frozenset(range(3))) == frozenset({0, 1, 2}) ``` @@ -1567,6 +1593,7 @@ def dict_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.dict_schema( keys_schema=core_schema.str_schema(), values_schema=core_schema.int_schema() ) @@ -1649,10 +1676,10 @@ def fn(v: bytes, info: core_schema.FieldValidationInfo) -> str: assert info.field_name is not None return v.decode() + 'world' - func_schema = core_schema.field_before_validator_function(function=fn, schema=core_schema.str_schema()) - schema = core_schema.typed_dict_schema( - {'a': core_schema.typed_dict_field(func_schema)} + func_schema = core_schema.field_before_validator_function( + function=fn, schema=core_schema.str_schema() ) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) v = SchemaValidator(schema) assert v.validate_python({'a': b'hello '}) == {'a': 'hello world'} @@ -1695,7 +1722,9 @@ def fn(v: Any, info: core_schema.ValidationInfo) -> str: assert 'hello' in v_str return v_str + 'world' - schema = core_schema.general_before_validator_function(function=fn, schema=core_schema.str_schema()) + schema = core_schema.general_before_validator_function( + function=fn, schema=core_schema.str_schema() + ) v = SchemaValidator(schema) assert v.validate_python(b'hello ') == "b'hello 'world" ``` @@ -1741,10 +1770,11 @@ def fn(v: str, info: core_schema.FieldValidationInfo) -> str: assert info.field_name is not None return v + 'world' - func_schema = core_schema.field_after_validator_function(function=fn, schema=core_schema.str_schema()) - schema = core_schema.typed_dict_schema( - {'a': core_schema.typed_dict_field(func_schema)} + func_schema = core_schema.field_after_validator_function( + function=fn, schema=core_schema.str_schema() ) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) v = SchemaValidator(schema) assert v.validate_python({'a': b'hello '}) == {'a': 'hello world'} @@ -1785,7 +1815,9 @@ def fn(v: str, info: core_schema.ValidationInfo) -> str: assert 'hello' in v return v + 'world' - schema = core_schema.general_after_validator_function(schema=core_schema.str_schema(), function=fn) + schema = core_schema.general_after_validator_function( + schema=core_schema.str_schema(), function=fn + ) v = SchemaValidator(schema) assert v.validate_python('hello ') == 'hello world' ``` @@ -1861,10 +1893,16 @@ def general_wrap_validator_function( ```py from pydantic_core import SchemaValidator, core_schema - def fn(v: str, validator: core_schema.ValidatorFunctionWrapHandler, info: core_schema.ValidationInfo) -> str: + def fn( + v: str, + validator: core_schema.ValidatorFunctionWrapHandler, + info: core_schema.ValidationInfo, + ) -> str: return validator(input_value=v) + 'world' - schema = core_schema.general_wrap_validator_function(function=fn, schema=core_schema.str_schema()) + schema = core_schema.general_wrap_validator_function( + function=fn, schema=core_schema.str_schema() + ) v = SchemaValidator(schema) assert v.validate_python('hello ') == 'hello world' ``` @@ -1903,15 +1941,19 @@ def field_wrap_validator_function( ```py from pydantic_core import SchemaValidator, core_schema - def fn(v: bytes, validator: core_schema.ValidatorFunctionWrapHandler, info: core_schema.FieldValidationInfo) -> str: + def fn( + v: bytes, + validator: core_schema.ValidatorFunctionWrapHandler, + info: core_schema.FieldValidationInfo, + ) -> str: assert info.data is not None assert info.field_name is not None return validator(v) + 'world' - func_schema = core_schema.field_wrap_validator_function(function=fn, schema=core_schema.str_schema()) - schema = core_schema.typed_dict_schema( - {'a': core_schema.typed_dict_field(func_schema)} + func_schema = core_schema.field_wrap_validator_function( + function=fn, schema=core_schema.str_schema() ) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) v = SchemaValidator(schema) assert v.validate_python({'a': b'hello '}) == {'a': 'hello world'} @@ -1961,7 +2003,7 @@ def fn(v: str, info: core_schema.ValidationInfo) -> str: schema = core_schema.general_plain_validator_function(function=fn) v = SchemaValidator(schema) - assert v.validate_python("hello ") == 'hello world' + assert v.validate_python('hello ') == 'hello world' ``` Args: @@ -1999,12 +2041,10 @@ def fn(v: Any, info: core_schema.FieldValidationInfo) -> str: return str(v) + 'world' func_schema = core_schema.field_plain_validator_function(function=fn) - schema = core_schema.typed_dict_schema( - {'a': core_schema.typed_dict_field(func_schema)} - ) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) v = SchemaValidator(schema) - assert v.validate_python({'a': "hello "}) == {'a': 'hello world'} + assert v.validate_python({'a': 'hello '}) == {'a': 'hello world'} ``` Args: @@ -2053,6 +2093,7 @@ def with_default_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.with_default_schema(core_schema.str_schema(), default='hello') wrapper_schema = core_schema.typed_dict_schema( {'a': core_schema.typed_dict_field(schema)} @@ -2108,6 +2149,7 @@ def nullable_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.nullable_schema(core_schema.str_schema()) v = SchemaValidator(schema) assert v.validate_python(None) is None @@ -2155,6 +2197,7 @@ def union_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.union_schema(core_schema.str_schema(), core_schema.int_schema()) v = SchemaValidator(schema) assert v.validate_python('hello') == 'hello' @@ -2220,6 +2263,7 @@ def tagged_union_schema( ```py from pydantic_core import SchemaValidator, core_schema + apple_schema = core_schema.typed_dict_schema( { 'foo': core_schema.typed_dict_field(core_schema.str_schema()), @@ -2229,7 +2273,9 @@ def tagged_union_schema( banana_schema = core_schema.typed_dict_schema( { 'foo': core_schema.typed_dict_field(core_schema.str_schema()), - 'spam': core_schema.typed_dict_field(core_schema.list_schema(items_schema=core_schema.int_schema())), + 'spam': core_schema.typed_dict_field( + core_schema.list_schema(items_schema=core_schema.int_schema()) + ), } ) schema = core_schema.tagged_union_schema( @@ -2241,7 +2287,10 @@ def tagged_union_schema( ) v = SchemaValidator(schema) assert v.validate_python({'foo': 'apple', 'bar': '123'}) == {'foo': 'apple', 'bar': 123} - assert v.validate_python({'foo': 'banana', 'spam': [1, 2, 3]}) == {'foo': 'banana', 'spam': [1, 2, 3]} + assert v.validate_python({'foo': 'banana', 'spam': [1, 2, 3]}) == { + 'foo': 'banana', + 'spam': [1, 2, 3], + } ``` Args: @@ -2301,9 +2350,11 @@ def fn(v: str, info: core_schema.ValidationInfo) -> str: return v + ' world' fn_schema = core_schema.general_plain_validator_function(function=fn) - schema = core_schema.chain_schema(fn_schema, fn_schema, fn_schema, core_schema.str_schema()) + schema = core_schema.chain_schema( + fn_schema, fn_schema, fn_schema, core_schema.str_schema() + ) v = SchemaValidator(schema) - assert v.validate_python("hello") == 'hello world world world' + assert v.validate_python('hello') == 'hello world world world' ``` Args: @@ -2347,11 +2398,15 @@ def fn(v: str, info: core_schema.ValidationInfo) -> str: lax_schema = core_schema.int_schema(strict=False) strict_schema = core_schema.int_schema(strict=True) - schema = core_schema.lax_or_strict_schema(lax_schema=lax_schema, strict_schema=strict_schema, strict=True) + schema = core_schema.lax_or_strict_schema( + lax_schema=lax_schema, strict_schema=strict_schema, strict=True + ) v = SchemaValidator(schema) assert v.validate_python(123) == 123 - schema = core_schema.lax_or_strict_schema(lax_schema=lax_schema, strict_schema=strict_schema, strict=False) + schema = core_schema.lax_or_strict_schema( + lax_schema=lax_schema, strict_schema=strict_schema, strict=False + ) v = SchemaValidator(schema) assert v.validate_python('123') == 123 ``` @@ -2400,7 +2455,8 @@ def typed_dict_field( Returns a schema that matches a typed dict field, e.g.: ```py - from pydantic_core import SchemaValidator, core_schema + from pydantic_core import core_schema + field = core_schema.typed_dict_field(schema=core_schema.int_schema(), required=True) ``` @@ -2460,6 +2516,7 @@ def typed_dict_schema( ```py from pydantic_core import SchemaValidator, core_schema + wrapper_schema = core_schema.typed_dict_schema( {'a': core_schema.typed_dict_field(core_schema.str_schema())} ) @@ -2595,7 +2652,10 @@ def dataclass_field( ```py from pydantic_core import SchemaValidator, core_schema - field = core_schema.dataclass_field(name='a', schema=core_schema.str_schema(), kw_only=False) + + field = core_schema.dataclass_field( + name='a', schema=core_schema.str_schema(), kw_only=False + ) schema = core_schema.dataclass_args_schema('Foobar', [field]) v = SchemaValidator(schema) assert v.validate_python({'a': 'hello'}) == ({'a': 'hello'}, None) @@ -2649,8 +2709,13 @@ def dataclass_args_schema( ```py from pydantic_core import SchemaValidator, core_schema - field_a = core_schema.dataclass_field(name='a', schema=core_schema.str_schema(), kw_only=False) - field_b = core_schema.dataclass_field(name='b', schema=core_schema.bool_schema(), kw_only=False) + + field_a = core_schema.dataclass_field( + name='a', schema=core_schema.str_schema(), kw_only=False + ) + field_b = core_schema.dataclass_field( + name='b', schema=core_schema.bool_schema(), kw_only=False + ) schema = core_schema.dataclass_args_schema('Foobar', [field_a, field_b]) v = SchemaValidator(schema) assert v.validate_python({'a': 'hello', 'b': True}) == ({'a': 'hello', 'b': True}, None) @@ -2742,7 +2807,10 @@ def arguments_parameter( ```py from pydantic_core import SchemaValidator, core_schema - param = core_schema.arguments_parameter(name='a', schema=core_schema.str_schema(), mode='positional_only') + + param = core_schema.arguments_parameter( + name='a', schema=core_schema.str_schema(), mode='positional_only' + ) schema = core_schema.arguments_schema(param) v = SchemaValidator(schema) assert v.validate_python(('hello',)) == (('hello',), {}) @@ -2782,8 +2850,13 @@ def arguments_schema( ```py from pydantic_core import SchemaValidator, core_schema - param_a = core_schema.arguments_parameter(name='a', schema=core_schema.str_schema(), mode='positional_only') - param_b = core_schema.arguments_parameter(name='b', schema=core_schema.bool_schema(), mode='positional_only') + + param_a = core_schema.arguments_parameter( + name='a', schema=core_schema.str_schema(), mode='positional_only' + ) + param_b = core_schema.arguments_parameter( + name='b', schema=core_schema.bool_schema(), mode='positional_only' + ) schema = core_schema.arguments_schema(param_a, param_b) v = SchemaValidator(schema) assert v.validate_python(('hello', True)) == (('hello', True), {}) @@ -2834,8 +2907,13 @@ def call_schema( ```py from pydantic_core import SchemaValidator, core_schema - param_a = core_schema.arguments_parameter(name='a', schema=core_schema.str_schema(), mode='positional_only') - param_b = core_schema.arguments_parameter(name='b', schema=core_schema.bool_schema(), mode='positional_only') + + param_a = core_schema.arguments_parameter( + name='a', schema=core_schema.str_schema(), mode='positional_only' + ) + param_b = core_schema.arguments_parameter( + name='b', schema=core_schema.bool_schema(), mode='positional_only' + ) args_schema = core_schema.arguments_schema(param_a, param_b) schema = core_schema.call_schema( @@ -2892,8 +2970,11 @@ def custom_error_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.custom_error_schema( - schema=core_schema.int_schema(), custom_error_type='MyError', custom_error_message="Error msg" + schema=core_schema.int_schema(), + custom_error_type='MyError', + custom_error_message='Error msg', ) v = SchemaValidator(schema) v.validate_python(1) @@ -2940,6 +3021,7 @@ def json_schema( ```py from pydantic_core import SchemaValidator, core_schema + dict_schema = core_schema.typed_dict_schema( { 'field_a': core_schema.typed_dict_field(core_schema.str_schema()), @@ -3000,6 +3082,7 @@ def url_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.url_schema() v = SchemaValidator(schema) # TODO: Assert this is equal to a constructed URL object @@ -3065,6 +3148,7 @@ def multi_host_url_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.multi_host_url_schema() v = SchemaValidator(schema) # TODO: Assert this is equal to a constructed URL object @@ -3113,6 +3197,7 @@ def definitions_schema(schema: CoreSchema, definitions: list[CoreSchema]) -> Def ```py from pydantic_core import SchemaValidator, core_schema + schema = core_schema.definitions_schema( core_schema.list_schema(core_schema.definition_reference_schema('foobar')), [core_schema.int_schema(ref='foobar')], @@ -3144,6 +3229,7 @@ def definition_reference_schema( ```py from pydantic_core import SchemaValidator, core_schema + schema_definition = core_schema.definition_reference_schema('list-schema') schema = core_schema.list_schema(items_schema=schema_definition, ref='list-schema') v = SchemaValidator(schema) diff --git a/tests/benchmarks/complete_schema.py b/tests/benchmarks/complete_schema.py index 98f3fc3d7a..71c86c7088 100644 --- a/tests/benchmarks/complete_schema.py +++ b/tests/benchmarks/complete_schema.py @@ -265,7 +265,7 @@ class BranchModel(BaseModel): class Model(BaseModel): field_str: str - field_str_con: constr(min_length=3, max_length=5, regex='^[a-z]+$') # noqa F722 + field_str_con: constr(min_length=3, max_length=5, regex='^[a-z]+$') field_int: int field_int_con: conint(gt=1, lt=10, multiple_of=2) field_float: float diff --git a/tests/requirements-linting.txt b/tests/requirements-linting.txt index 44a290ee70..4faa4f447d 100644 --- a/tests/requirements-linting.txt +++ b/tests/requirements-linting.txt @@ -1,4 +1,4 @@ -black==22.12.0 -ruff==0.0.239 +black==23.1.0 +ruff==0.0.259 isort[colors]==5.10.1 pyright==1.1.296 diff --git a/tests/requirements.txt b/tests/requirements.txt index c5bc53b2ee..1ef5ede0b9 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,9 +2,10 @@ coverage==7.0.5 dirty-equals==0.5.0 hypothesis==6.63.0 pytest==7.2.1 +pytest-examples==0.0.4 pytest-speed==0.3.5 pytest-mock==3.10.0 -pytest-pretty==1.0.1 +pytest-pretty==1.1.1 pytest-timeout==2.1.0 pydantic==1.10.4;python_version>="3.8" pytz==2022.7.1 diff --git a/tests/test_docstrings.py b/tests/test_docstrings.py index 075bb11482..10ff4c6576 100644 --- a/tests/test_docstrings.py +++ b/tests/test_docstrings.py @@ -1,99 +1,36 @@ -import inspect -import re import sys -from io import StringIO -from tempfile import NamedTemporaryFile -from typing import Any, TextIO import pytest -import pydantic_core - -DOCSTRING_REGEX = r'```py(.*?)```' - - -class DocstringTest: - def method_a(self): - """ - ```py - assert 1 == 1 - assert 1 != 2 - ``` - - ```py - assert 1 != 3 - assert 2 + 2 == 4 - ``` - """ - pass - - def method_b(self): - """ - ```py - print('hello') - print('world') - ``` - """ - pass - - -class DocstringTestBadIndent: - def method_a(self): - """ - ```py - assert 1 == 1 - print('badly indented line') - ``` - """ - pass - - -def write_docstrings_to_test_file(obj_with_docstrings: Any, f: TextIO): - for name, obj in inspect.getmembers(obj_with_docstrings): - if obj.__doc__ is not None: - for i, match in enumerate(re.finditer(DOCSTRING_REGEX, obj.__doc__, re.DOTALL)): - code = match.group(1) - f.write(f'def test_{name}_{i}():\n') - lines = [line for line in code.splitlines() if line.strip()] - initial_indent = len(lines[0]) - len(lines[0].lstrip()) - for line in lines: - if line[:initial_indent].strip(): - raise ValueError(f'Unexpected indentation: {line}') - f.write(f' {line[initial_indent:]}\n') - f.write('\n') - f.flush() - - -def test_write_docstrings_to_test_file(): - with StringIO('') as f: - write_docstrings_to_test_file(DocstringTest, f) - assert ( - f.getvalue() - == """def test_method_a_0(): - assert 1 == 1 - assert 1 != 2 - -def test_method_a_1(): - assert 1 != 3 - assert 2 + 2 == 4 - -def test_method_b_0(): - print('hello') - print('world') - -""" - ) - - -def test_write_docstrings_to_test_file_raises_value_error(): - with StringIO('') as f, pytest.raises(ValueError): - write_docstrings_to_test_file(DocstringTestBadIndent, f) - - -@pytest.mark.skipif(sys.platform == 'win32', reason='Windows does not support NamedTemporaryFile') -def test_docstrings(): - with NamedTemporaryFile('w', suffix='.py') as f: - write_docstrings_to_test_file(pydantic_core.core_schema, f) - exit_code = pytest.main([f.name]) - if exit_code != 0: - sys.exit(exit_code) +try: + from pytest_examples import CodeExample, EvalExample, find_examples +except ImportError: + # pytest_examples is not installed on emscripten + CodeExample = EvalExample = None + + def find_examples(*_directories): + return [] + + +@pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Only both on linux and macos') +@pytest.mark.parametrize('example', find_examples('pydantic_core/core_schema.py'), ids=str) +def test_docstrings(example: CodeExample, eval_example: EvalExample): + eval_example.set_config(quotes='single') + + if eval_example.update_examples: + eval_example.format(example) + eval_example.run_print_update(example) + else: + eval_example.lint(example) + eval_example.run_print_check(example) + + +@pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Only both on linux and macos') +@pytest.mark.parametrize('example', find_examples('README.md'), ids=str) +def test_readme(example: CodeExample, eval_example: EvalExample): + eval_example.set_config(line_length=100, quotes='single') + if eval_example.update_examples: + eval_example.format(example) + else: + eval_example.lint(example) + eval_example.run(example) diff --git a/tests/test_errors.py b/tests/test_errors.py index 1bebe2976b..f6c18f5ecb 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -397,7 +397,6 @@ def __repr__(self): def test_error_on_repr(): - s = SchemaValidator({'type': 'int'}) with pytest.raises(ValidationError) as exc_info: s.validate_python(BadRepr()) diff --git a/tests/test_misc.py b/tests/test_misc.py index cf463edc33..21976c6a8e 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1,6 +1,4 @@ import re -import sys -from pathlib import Path import pytest from typing_extensions import get_args @@ -138,14 +136,6 @@ class MyModel: ) -@pytest.mark.skipif(sys.platform == 'emscripten', reason='README.md is not mounted in wasm file system') -def test_readme(import_execute): - this_dir = Path(__file__).parent - readme = (this_dir / '..' / 'README.md').read_text() - example_code = re.search(r'\n```py\n(.*?)\n```\n', readme, re.M | re.S).group(1) - import_execute(example_code) - - def test_core_schema_type_literal(): def get_type_value(schema): type_ = schema.__annotations__['type'] diff --git a/tests/validators/test_dataclasses.py b/tests/validators/test_dataclasses.py index d443c7b764..e80f4c7b3a 100644 --- a/tests/validators/test_dataclasses.py +++ b/tests/validators/test_dataclasses.py @@ -406,7 +406,6 @@ def __post_init__(self, *args): ], ) def test_dataclass_exact_validation(input_value, expected): - schema = core_schema.dataclass_schema( FooDataclass, core_schema.dataclass_args_schema( diff --git a/tests/validators/test_model_init.py b/tests/validators/test_model_init.py index 817d850b64..7ade1d8d9b 100644 --- a/tests/validators/test_model_init.py +++ b/tests/validators/test_model_init.py @@ -9,7 +9,6 @@ class MyModel: def test_model_init(): - v = SchemaValidator( { 'type': 'model',