From e7227db41a7e872b79749605e80dc274aa2ee559 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Mon, 14 Oct 2019 16:40:25 +0100 Subject: [PATCH] Insert prints in docs. (#895) * starting insert prints * working exec_script * remove prints, fix exec_examples.py * more cleanup of examples, better model printing * upgrade netlify runtime * extra docs deps * few more small tweaks --- .gitignore | 3 +- docs/benchmarks.md | 2 +- docs/build/exec_examples.py | 164 ++++++++++++++++++ docs/build/main.py | 14 +- docs/changelog.md | 2 +- docs/examples/.editorconfig | 6 + docs/examples/advanced_exclude1.py | 11 +- docs/examples/advanced_exclude2.py | 16 +- docs/examples/alias_generator_config.py | 5 - docs/examples/bare_type_type.py | 8 - docs/examples/boolean.py | 9 - docs/examples/callable.py | 1 - docs/examples/choices.py | 14 +- docs/examples/config.py | 7 - docs/examples/constrained_types.py | 27 +-- docs/examples/custom_data_types.py | 16 -- docs/examples/custom_root_field.py | 21 --- docs/examples/data_conversion.py | 1 - docs/examples/datetime_example.py | 7 - docs/examples/dynamic_inheritance.py | 13 +- docs/examples/dynamic_model_creation.py | 1 - docs/examples/errors1.py | 46 ----- docs/examples/errors2.py | 9 - docs/examples/errors3.py | 12 -- docs/examples/ex_abc.py | 1 - docs/examples/ex_color_type.py | 15 -- docs/examples/ex_dataclasses.py | 2 - docs/examples/ex_dataclasses_config.py | 8 - docs/examples/ex_json_type.py | 22 --- docs/examples/ex_nested_dataclasses.py | 1 - docs/examples/ex_post_init_post_parse.py | 4 - docs/examples/ex_secret_types.py | 17 +- docs/examples/ex_typing.py | 17 +- docs/examples/example1.py | 11 -- docs/examples/example2.py | 2 + docs/examples/example2_output.json | 24 --- docs/examples/export_copy.py | 9 - docs/examples/export_dict.py | 7 +- docs/examples/export_iterate.py | 5 - docs/examples/export_json.py | 3 - docs/examples/export_pickle.py | 5 - docs/examples/field_order.py | 8 +- docs/examples/forward_ref.py | 2 - docs/examples/generics-naming.py | 2 - docs/examples/generics.py | 22 --- docs/examples/json_orjson.py | 4 +- docs/examples/json_ujson.py | 3 +- docs/examples/literal1.py | 5 - docs/examples/literal2.py | 9 - docs/examples/literal3.py | 4 - docs/examples/mutation.py | 7 - docs/examples/mypy.py | 2 - docs/examples/orm_mode.py | 5 - docs/examples/orm_mode_recursive.py | 6 - docs/examples/parse.py | 17 +- docs/examples/postponed_annotations.py | 1 - docs/examples/postponed_broken.py | 4 +- docs/examples/recursive.py | 9 - docs/examples/schema1.json | 50 ------ docs/examples/schema1.py | 8 +- docs/examples/schema2.json | 40 ----- docs/examples/schema2.py | 10 -- docs/examples/schema3.json | 29 ---- docs/examples/schema3.py | 10 +- docs/examples/schema4.json | 24 --- docs/examples/schema4.py | 9 - docs/examples/self_referencing_annotations.py | 2 - docs/examples/self_referencing_string.py | 2 - docs/examples/settings.py | 26 +-- docs/examples/settings_case_sensitive.py | 1 - docs/examples/strict_types.py | 25 +-- docs/examples/type_type.py | 6 - docs/examples/union_type_correct.py | 5 - docs/examples/union_type_incorrect.py | 11 -- docs/examples/url_properties.py | 15 +- docs/examples/url_punycode.py | 5 - docs/examples/urls.py | 13 -- docs/examples/validators_always.py | 5 - docs/examples/validators_dataclass.py | 5 - docs/examples/validators_pre_item.py | 15 +- docs/examples/validators_root.py | 15 +- docs/examples/validators_simple.py | 14 +- docs/index.md | 10 +- docs/requirements.txt | 3 + docs/usage/dataclasses.md | 8 +- docs/usage/exporting_models.md | 18 +- docs/usage/model_config.md | 6 +- docs/usage/models.md | 32 ++-- docs/usage/mypy.md | 2 +- docs/usage/postponed_annotations.md | 12 +- docs/usage/schema.md | 18 +- docs/usage/settings.md | 4 +- docs/usage/types.md | 44 ++--- docs/usage/validators.md | 10 +- runtime.txt | 2 +- 95 files changed, 335 insertions(+), 857 deletions(-) create mode 100755 docs/build/exec_examples.py create mode 100644 docs/examples/.editorconfig delete mode 100644 docs/examples/example2_output.json delete mode 100644 docs/examples/schema1.json delete mode 100644 docs/examples/schema2.json delete mode 100644 docs/examples/schema3.json delete mode 100644 docs/examples/schema4.json diff --git a/.gitignore b/.gitignore index 2c47aba..72fb52c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ env36/ env37/ *.py[cod] *.egg-info/ -build/ +/build/ dist/ .cache/ .mypy_cache/ @@ -15,6 +15,7 @@ test.py /docs/.changelog.md /docs/.version.md /docs/.tmp_schema_mappings.html +/docs/.tmp_examples/ /site/ /site.zip .pytest_cache/ diff --git a/docs/benchmarks.md b/docs/benchmarks.md index b676931..a48d5c1 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -1,6 +1,6 @@ Below are the results of crude benchmarks comparing *pydantic* to other validation libraries. -{!./.benchmarks_table.md!} +{!.benchmarks_table.md!} See [the benchmarks code](https://github.com/samuelcolvin/pydantic/tree/master/benchmarks) for more details on the test case. Feel free to suggest more packages to benchmark or improve an existing one. diff --git a/docs/build/exec_examples.py b/docs/build/exec_examples.py new file mode 100755 index 0000000..cafd2e1 --- /dev/null +++ b/docs/build/exec_examples.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +import importlib +import inspect +import json +import os +import re +import shutil +import sys +import textwrap +import traceback +from pathlib import Path +from typing import Any +from unittest.mock import patch + +from devtools import PrettyFormat +from pydantic import BaseModel + +THIS_DIR = Path(__file__).parent +DOCS_DIR = (THIS_DIR / '..').resolve() +EXAMPLES_ROOT = DOCS_DIR / 'examples' +TMP_EXAMPLES_ROOT = DOCS_DIR / '.tmp_examples' +MAX_LINE_LENGTH = int(re.search(r'max_line_length = (\d+)', (EXAMPLES_ROOT / '.editorconfig').read_text()).group(1)) +LONG_LINE = 50 +pformat = PrettyFormat(simple_cutoff=LONG_LINE) +PRINT_TO_JSON = {'example2.py', 'schema1.py', 'schema2.py', 'schema3.py', 'schema4.py'} +ENVIRON = {'my_auth_key': 'xxx', 'my_api_key': 'xxx'} + + +def to_string(value: Any) -> str: + # attempt to build a pretty version + if isinstance(value, BaseModel): + s = str(value) + if len(s) > LONG_LINE: + indent = ' ' * (len(value.__class__.__name__) + 1) + return value.__class__.__name__ + ' ' + f'\n{indent}'.join(f'{k}={v!r}' for k, v in value.__dict__.items()) + else: + return s + if isinstance(value, (dict, list, tuple, set)): + return pformat(value) + elif isinstance(value, str) and any(re.fullmatch(r, value, flags=re.DOTALL) for r in ['{".+}', r'\[.+\]']): + try: + obj = json.loads(value) + except ValueError: + # not JSON, not a problem + pass + else: + s = json.dumps(obj) + if len(s) > LONG_LINE: + json.dumps(obj, indent=2) + else: + return s + + return str(value) + + +class MockPrint: + def __init__(self, file: Path): + self.file = file + self.statements = [] + + def __call__(self, *args): + frame = inspect.currentframe().f_back.f_back.f_back + if not self.file.samefile(frame.f_code.co_filename): + # sys.stdout.write(' '.join(map(str, args))) + raise RuntimeError("what's wrong here?") + s = ' '.join(map(to_string, args)) + + lines = [] + for line in s.split('\n'): + if len(line) > MAX_LINE_LENGTH - 3: + lines += textwrap.wrap(line, width=MAX_LINE_LENGTH - 3) + else: + lines.append(line) + self.statements.append((frame.f_lineno, lines)) + + +def all_md_contents() -> str: + file_contents = [] + for f in DOCS_DIR.glob('**/*.md'): + file_contents.append(f.read_text()) + return '\n\n\n'.join(file_contents) + + +def exec_examples(): + errors = [] + all_md = all_md_contents() + new_files = {} + os.environ.clear() + os.environ.update(ENVIRON) + + sys.path.append(str(EXAMPLES_ROOT)) + for file in sorted(EXAMPLES_ROOT.iterdir()): + + def error(desc: str): + errors.append((file, desc)) + sys.stderr.write(f'{file.name} Error: {desc}\n') + + if not file.is_file(): + # __pycache__, maybe others + continue + + if file.suffix != '.py': + # just copy + new_files[file.name] = file.read_text() + continue + + if f'{{!.tmp_examples/{file.name}!}}' not in all_md: + error('file not used anywhere') + mp = MockPrint(file) + with patch('builtins.print') as mock_print: + mock_print.side_effect = mp + try: + importlib.import_module(file.stem) + except Exception: + tb = traceback.format_exception(*sys.exc_info()) + error(''.join(e for e in tb if '/pydantic/docs/examples/' in e or not e.startswith(' File '))) + + file_text = file.read_text() + if '\n\n\n' in file_text: + error('too many new lines') + if not file_text.endswith('\n'): + error('no trailing new line') + lines = file_text.split('\n') + + if any(len(l) > MAX_LINE_LENGTH for l in lines): + error(f'lines longer than {MAX_LINE_LENGTH} characters') + + if file.name in PRINT_TO_JSON: + if len(mp.statements) != 1: + error('should only have one print statement') + new_files[file.stem + '.json'] = '\n'.join(mp.statements[0][1]) + '\n' + + else: + for line_no, print_lines in reversed(mp.statements): + if len(print_lines) > 2: + text = '"""\n{}\n"""'.format('\n'.join(print_lines)) + else: + text = '\n'.join('#> ' + l for l in print_lines) + lines.insert(line_no, text) + + try: + ignore_above = lines.index('# === ignore above') + except ValueError: + pass + else: + lines = lines[ignore_above + 1 :] + + new_files[file.name] = '\n'.join(lines) + + if errors: + return 1 + + if TMP_EXAMPLES_ROOT.exists(): + shutil.rmtree(TMP_EXAMPLES_ROOT) + + print(f'writing {len(new_files)} example files to {TMP_EXAMPLES_ROOT}') + TMP_EXAMPLES_ROOT.mkdir() + for file_name, content in new_files.items(): + (TMP_EXAMPLES_ROOT / file_name).write_text(content) + return 0 + + +if __name__ == '__main__': + sys.exit(exec_examples()) diff --git a/docs/build/main.py b/docs/build/main.py index e68925c..005ae1b 100755 --- a/docs/build/main.py +++ b/docs/build/main.py @@ -16,14 +16,16 @@ def main(): (PROJECT_ROOT / 'docs/.changelog.md').write_text(history) - sys.path.append(str(THIS_DIR.resolve())) - from schema_mapping import build_schema_mappings - - build_schema_mappings() - version = SourceFileLoader('version', str(PROJECT_ROOT / 'pydantic/version.py')).load_module() (PROJECT_ROOT / 'docs/.version.md').write_text(f'Documentation for version: **v{version.VERSION}**\n') + sys.path.append(str(THIS_DIR.resolve())) + from schema_mapping import build_schema_mappings + from exec_examples import exec_examples + + build_schema_mappings() + return exec_examples() + if __name__ == '__main__': - main() + sys.exit(main()) diff --git a/docs/changelog.md b/docs/changelog.md index 3f3f1da..5df42d6 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1 +1 @@ -{!./.changelog.md!} +{!.changelog.md!} diff --git a/docs/examples/.editorconfig b/docs/examples/.editorconfig new file mode 100644 index 0000000..e65b127 --- /dev/null +++ b/docs/examples/.editorconfig @@ -0,0 +1,6 @@ +root = true + +[*.py] +indent_style = space +indent_size = 4 +max_line_length = 80 diff --git a/docs/examples/advanced_exclude1.py b/docs/examples/advanced_exclude1.py index 058d6a2..fc6c444 100644 --- a/docs/examples/advanced_exclude1.py +++ b/docs/examples/advanced_exclude1.py @@ -10,7 +10,7 @@ class Transaction(BaseModel): user: User value: int -transaction = Transaction( +t = Transaction( id="1234567890", user=User( id=42, @@ -21,12 +21,9 @@ transaction = Transaction( ) # using a set: -print(transaction.dict(exclude={'user', 'value'})) -#> {'id': '1234567890'} +print(t.dict(exclude={'user', 'value'})) # using a dict: -print(transaction.dict(exclude={'user': {'username', 'password'}, 'value': ...})) -#> {'id': '1234567890', 'user': {'id': 42}} +print(t.dict(exclude={'user': {'username', 'password'}, 'value': ...})) -print(transaction.dict(include={'id': ..., 'user': {'id'}})) -#> {'id': '1234567890', 'user': {'id': 42}} +print(t.dict(include={'id': ..., 'user': {'id'}})) diff --git a/docs/examples/advanced_exclude2.py b/docs/examples/advanced_exclude2.py index b9d1bcf..1c514e4 100644 --- a/docs/examples/advanced_exclude2.py +++ b/docs/examples/advanced_exclude2.py @@ -51,7 +51,8 @@ exclude_keys = { 'second_name': ..., 'address': {'post_code': ..., 'country': {'phone_code'}}, 'card_details': ..., - 'hobbies': {-1: {'info'}}, # You can exclude values from tuples and lists by indexes + # You can exclude values from tuples and lists by indexes + 'hobbies': {-1: {'info'}}, } include_keys = { @@ -60,14 +61,5 @@ include_keys = { 'hobbies': {0: ..., -1: {'name'}} } -print( - user.dict(include=include_keys) == user.dict(exclude=exclude_keys) == { - 'first_name': 'John', - 'address': {'country': {'name': 'USA'}}, - 'hobbies': [ - {'name': 'Programming', 'info': 'Writing code and stuff'}, - {'name': 'Gaming'} - ] - } -) -#> True +# would be the same as user.dict(exclude=exclude_keys) in this case: +print(user.dict(include=include_keys)) diff --git a/docs/examples/alias_generator_config.py b/docs/examples/alias_generator_config.py index ea5d8e3..c4f207c 100644 --- a/docs/examples/alias_generator_config.py +++ b/docs/examples/alias_generator_config.py @@ -14,8 +14,3 @@ class Voice(BaseModel): voice = Voice(Name='Filiz', Gender='Female', LanguageCode='tr-TR') print(voice.language_code) print(voice.dict(by_alias=True)) - -""" -tr-TR -{'Name': 'Filiz', 'Gender': 'Female', 'LanguageCode': 'tr-TR'} -""" diff --git a/docs/examples/bare_type_type.py b/docs/examples/bare_type_type.py index bbe45ed..3afcf25 100644 --- a/docs/examples/bare_type_type.py +++ b/docs/examples/bare_type_type.py @@ -2,23 +2,15 @@ from typing import Type from pydantic import BaseModel, ValidationError - class Foo: pass - class LenientSimpleModel(BaseModel): any_class_goes: Type - LenientSimpleModel(any_class_goes=int) LenientSimpleModel(any_class_goes=Foo) try: LenientSimpleModel(any_class_goes=Foo()) except ValidationError as e: print(e) -""" -1 validation error -any_class_goes - subclass of type expected (type=type_error.class) -""" diff --git a/docs/examples/boolean.py b/docs/examples/boolean.py index 88c7402..bb2cf8f 100644 --- a/docs/examples/boolean.py +++ b/docs/examples/boolean.py @@ -4,17 +4,8 @@ class BooleanModel(BaseModel): bool_value: bool print(BooleanModel(bool_value=False)) -#> BooleansModel bool_value=False - print(BooleanModel(bool_value='False')) -#> BooleansModel bool_value=False - try: BooleanModel(bool_value=[]) except ValidationError as e: print(str(e)) -""" -1 validation error -bool_value - value could not be parsed to a boolean (type=type_error.bool) -""" diff --git a/docs/examples/callable.py b/docs/examples/callable.py index 801680f..fb89583 100644 --- a/docs/examples/callable.py +++ b/docs/examples/callable.py @@ -6,4 +6,3 @@ class Foo(BaseModel): m = Foo(callback=lambda x: x) print(m) -#> Foo callback= at 0x7f16bc73e1e0> diff --git a/docs/examples/choices.py b/docs/examples/choices.py index d198238..f4cf3c1 100644 --- a/docs/examples/choices.py +++ b/docs/examples/choices.py @@ -1,26 +1,22 @@ from enum import Enum, IntEnum -from pydantic import BaseModel - +from pydantic import BaseModel, ValidationError class FruitEnum(str, Enum): pear = 'pear' banana = 'banana' - class ToolEnum(IntEnum): spanner = 1 wrench = 2 - class CookingModel(BaseModel): fruit: FruitEnum = FruitEnum.pear tool: ToolEnum = ToolEnum.spanner - print(CookingModel()) -#> CookingModel fruit= tool= print(CookingModel(tool=2, fruit='banana')) -#> CookingModel fruit= tool= -print(CookingModel(fruit='other')) -# will raise a validation error +try: + CookingModel(fruit='other') +except ValidationError as e: + print(e) diff --git a/docs/examples/config.py b/docs/examples/config.py index dea2dd7..f6022ac 100644 --- a/docs/examples/config.py +++ b/docs/examples/config.py @@ -1,6 +1,5 @@ from pydantic import BaseModel, ValidationError - class Model(BaseModel): v: str @@ -10,13 +9,7 @@ class Model(BaseModel): 'value_error.any_str.max_length': 'max_length:{limit_value}', } - try: Model(v='x' * 20) except ValidationError as e: print(e) -""" -1 validation error -v - max_length:10 (type=value_error.any_str.max_length; limit_value=10) -""" diff --git a/docs/examples/constrained_types.py b/docs/examples/constrained_types.py index cd252d1..3e80df9 100644 --- a/docs/examples/constrained_types.py +++ b/docs/examples/constrained_types.py @@ -14,7 +14,6 @@ from pydantic import ( constr, ) - class Model(BaseModel): short_bytes: conbytes(min_length=2, max_length=10) strip_bytes: conbytes(strip_whitespace=True) @@ -41,7 +40,6 @@ class Model(BaseModel): decimal_max_digits_and_places: condecimal(max_digits=2, decimal_places=2) mod_decimal: condecimal(multiple_of=Decimal('0.25')) - m = Model( short_bytes=b'foo', strip_bytes=b' bar', @@ -63,27 +61,4 @@ m = Model( decimal_max_digits_and_places='0.99', mod_decimal='2.75', ) -debug(m.dict()) -""" -{ - 'short_bytes': b'foo', - 'strip_bytes': b'bar', - 'short_str': 'foo', - 'regex_str': 'apple pie', - 'strip_str': 'bar', - 'big_int': 1001, - 'mod_int': 155, - 'pos_int': 1, - 'neg_int': -1, - 'big_float': 1002.1, - 'unit_interval': 0.5, - 'mod_float': 1.5, - 'pos_float': 2.2, - 'neg_float': -2.3, - 'short_list': [1, 2], - 'decimal_positive': Decimal('21.12'), - 'decimal_negative': Decimal('-21.12'), - 'decimal_max_digits_and_places': Decimal('0.99'), - 'mod_decimal': Decimal('2.75'), -} -""" +print(m.dict()) diff --git a/docs/examples/custom_data_types.py b/docs/examples/custom_data_types.py index d7cf5cf..165b42b 100644 --- a/docs/examples/custom_data_types.py +++ b/docs/examples/custom_data_types.py @@ -1,6 +1,5 @@ from pydantic import BaseModel, ValidationError - class StrictStr(str): @classmethod def __get_validators__(cls): @@ -12,26 +11,11 @@ class StrictStr(str): raise ValueError(f'strict string: str expected not {type(v)}') return v - class Model(BaseModel): s: StrictStr - print(Model(s='hello')) -#> Model s='hello' - try: print(Model(s=123)) except ValidationError as e: print(e.json()) -""" -[ - { - "loc": [ - "s" - ], - "msg": "strict string: str expected not ", - "type": "value_error" - } -] -""" diff --git a/docs/examples/custom_root_field.py b/docs/examples/custom_root_field.py index 309ded8..bdf55b7 100644 --- a/docs/examples/custom_root_field.py +++ b/docs/examples/custom_root_field.py @@ -7,29 +7,8 @@ class Pets(BaseModel): __root__: List[str] print(Pets(__root__=['dog', 'cat'])) -#> Pets __root__=['dog', 'cat'] - print(Pets(__root__=['dog', 'cat']).json()) -#> ["dog", "cat"] - print(Pets.parse_obj(['dog', 'cat'])) -#> Pets __root__=['dog', 'cat'] - print(Pets.schema()) -#> {'title': 'Pets', 'type': 'array', 'items': {'type': 'string'}} - pets_schema = schema([Pets]) print(json.dumps(pets_schema, indent=2)) -""" -{ - "definitions": { - "Pets": { - "title": "Pets", - "type": "array", - "items": { - "type": "string" - } - } - } -} -""" diff --git a/docs/examples/data_conversion.py b/docs/examples/data_conversion.py index cc1723f..27f9b66 100644 --- a/docs/examples/data_conversion.py +++ b/docs/examples/data_conversion.py @@ -6,4 +6,3 @@ class Model(BaseModel): c: str print(Model(a=3.1415, b=' 2.72 ', c=123).dict()) -#> {'a': 3, 'b': 2.72, 'c': '123'} diff --git a/docs/examples/datetime_example.py b/docs/examples/datetime_example.py index 6d15035..f2d0b03 100644 --- a/docs/examples/datetime_example.py +++ b/docs/examples/datetime_example.py @@ -7,7 +7,6 @@ class Model(BaseModel): t: time = None td: timedelta = None - m = Model( d=1966280412345.6789, dt='2032-04-23T10:20:30.400+02:30', @@ -16,9 +15,3 @@ m = Model( ) print(m.dict()) -#> { -#> 'd': datetime.date(2032, 4, 22), -#> 'dt': datetime.datetime(2032, 4, 23, 10, 20, 30, 400000, tzinfo=datetime.timezone(datetime.timedelta(seconds=9000))), -#> 't': datetime.time(4, 8, 16), -#> 'td': datetime.timedelta(days=3, seconds=45005) -#> } diff --git a/docs/examples/dynamic_inheritance.py b/docs/examples/dynamic_inheritance.py index a46a723..3a99e90 100644 --- a/docs/examples/dynamic_inheritance.py +++ b/docs/examples/dynamic_inheritance.py @@ -1,13 +1,14 @@ from pydantic import BaseModel, create_model - class FooModel(BaseModel): foo: str bar: int = 123 - -BarModel = create_model('BarModel', apple='russet', banana='yellow', __base__=FooModel) +BarModel = create_model( + 'BarModel', + apple='russet', + banana='yellow', + __base__=FooModel, +) print(BarModel) -#> -print(', '.join(BarModel.__fields__.keys())) -#> foo, bar, apple, banana +print(BarModel.__fields__.keys()) diff --git a/docs/examples/dynamic_model_creation.py b/docs/examples/dynamic_model_creation.py index 7e5d5c3..6c9ea30 100644 --- a/docs/examples/dynamic_model_creation.py +++ b/docs/examples/dynamic_model_creation.py @@ -2,7 +2,6 @@ from pydantic import BaseModel, create_model DynamicFoobarModel = create_model('DynamicFoobarModel', foo=(str, ...), bar=123) - class StaticFoobarModel(BaseModel): foo: str bar: int = 123 diff --git a/docs/examples/errors1.py b/docs/examples/errors1.py index 1861479..2c30782 100644 --- a/docs/examples/errors1.py +++ b/docs/examples/errors1.py @@ -23,54 +23,8 @@ try: Model(**data) except ValidationError as e: print(e) -""" -5 validation errors -list_of_ints -> 2 - value is not a valid integer (type=type_error.integer) -a_float - value is not a valid float (type=type_error.float) -is_required - field required (type=value_error.missing) -recursive_model -> lng - value is not a valid float (type=type_error.float) -gt_int - ensure this value is greater than 42 (type=value_error.number.gt; limit_value=42) -""" try: Model(**data) except ValidationError as e: print(e.json()) - -""" -[ - { - "loc": ["is_required"], - "msg": "field required", - "type": "value_error.missing" - }, - { - "loc": ["gt_int"], - "msg": "ensure this value is greater than 42", - "type": "value_error.number.gt", - "ctx": { - "limit_value": 42 - } - }, - { - "loc": ["list_of_ints", 2], - "msg": "value is not a valid integer", - "type": "type_error.integer" - }, - { - "loc": ["a_float"], - "msg": "value is not a valid float", - "type": "type_error.float" - }, - { - "loc": ["recursive_model", "lng"], - "msg": "value is not a valid float", - "type": "type_error.float" - } -] -""" diff --git a/docs/examples/errors2.py b/docs/examples/errors2.py index 41b608a..88f06d4 100644 --- a/docs/examples/errors2.py +++ b/docs/examples/errors2.py @@ -15,12 +15,3 @@ try: except ValidationError as e: print(e.errors()) -""" -[ - { - 'loc': ('foo',), - 'msg': 'value must be "bar"', - 'type': 'value_error', - }, -] -""" diff --git a/docs/examples/errors3.py b/docs/examples/errors3.py index 472999d..4c54bef 100644 --- a/docs/examples/errors3.py +++ b/docs/examples/errors3.py @@ -17,15 +17,3 @@ try: Model(foo='ber') except ValidationError as e: print(e.json()) -""" -[ - { - "loc": ["foo"], - "msg": "value is not \"bar\", got \"ber\"", - "type": "value_error.not_a_bar", - "ctx": { - "wrong_value": "ber" - } - } -] -""" diff --git a/docs/examples/ex_abc.py b/docs/examples/ex_abc.py index f325199..3e7c04a 100644 --- a/docs/examples/ex_abc.py +++ b/docs/examples/ex_abc.py @@ -1,7 +1,6 @@ import abc from pydantic import BaseModel - class FooBarModel(BaseModel, abc.ABC): a: str b: int diff --git a/docs/examples/ex_color_type.py b/docs/examples/ex_color_type.py index 07ee384..c78cb66 100644 --- a/docs/examples/ex_color_type.py +++ b/docs/examples/ex_color_type.py @@ -3,31 +3,16 @@ from pydantic.color import Color c = Color('ff00ff') print(c.as_named()) -#> magenta print(c.as_hex()) -#> #f0f - c2 = Color('green') print(c2.as_rgb_tuple()) -#> (0, 128, 0, 1) print(c2.original()) -#> green print(repr(Color('hsl(180, 100%, 50%)'))) -#> - class Model(BaseModel): color: Color print(Model(color='purple')) -#> Model color= - try: Model(color='hello') except ValidationError as e: print(e) -""" -1 validation error -color - value is not a valid color: string not recognised as a valid color - (type=value_error.color; reason=string not recognised as a valid color) -""" diff --git a/docs/examples/ex_dataclasses.py b/docs/examples/ex_dataclasses.py index 931da02..16e4178 100644 --- a/docs/examples/ex_dataclasses.py +++ b/docs/examples/ex_dataclasses.py @@ -7,7 +7,5 @@ class User: name: str = 'John Doe' signup_ts: datetime = None - user = User(id='42', signup_ts='2032-06-21T12:00') print(user) -#> User(id=42, name='John Doe', signup_ts=datetime.datetime(2032, 6, 21, 12, 0)) diff --git a/docs/examples/ex_dataclasses_config.py b/docs/examples/ex_dataclasses_config.py index bdb2e49..92fdb0b 100644 --- a/docs/examples/ex_dataclasses_config.py +++ b/docs/examples/ex_dataclasses_config.py @@ -3,7 +3,6 @@ from datetime import datetime from pydantic import ValidationError from pydantic.dataclasses import dataclass - class MyConfig: max_anystr_length = 10 validate_assignment = True @@ -11,21 +10,14 @@ class MyConfig: 'value_error.any_str.max_length': 'max_length:{limit_value}', } - @dataclass(config=MyConfig) class User: id: int name: str = 'John Doe' signup_ts: datetime = None - user = User(id='42', signup_ts='2032-06-21T12:00') try: user.name = 'x' * 20 except ValidationError as e: print(e) -""" -1 validation error -name - max_length:10 (type=value_error.any_str.max_length; limit_value=10) -""" diff --git a/docs/examples/ex_json_type.py b/docs/examples/ex_json_type.py index 7b94e2a..26b37ec 100644 --- a/docs/examples/ex_json_type.py +++ b/docs/examples/ex_json_type.py @@ -9,40 +9,18 @@ class ComplexJsonModel(BaseModel): json_obj: Json[List[int]] print(SimpleJsonModel(json_obj='{"b": 1}')) -#> SimpleJsonModel json_obj={'b': 1} - print(ComplexJsonModel(json_obj='[1, 2, 3]')) -#> ComplexJsonModel json_obj=[1, 2, 3] - - try: ComplexJsonModel(json_obj=12) except ValidationError as e: print(e) -""" -1 validation error -json_obj - JSON object must be str, bytes or bytearray (type=type_error.json) -""" try: ComplexJsonModel(json_obj='[a, b]') except ValidationError as e: print(e) -""" -1 validation error -json_obj - Invalid JSON (type=value_error.json) -""" try: ComplexJsonModel(json_obj='["a", "b"]') except ValidationError as e: print(e) -""" -2 validation errors -json_obj -> 0 - value is not a valid integer (type=type_error.integer) -json_obj -> 1 - value is not a valid integer (type=type_error.integer) -""" diff --git a/docs/examples/ex_nested_dataclasses.py b/docs/examples/ex_nested_dataclasses.py index 433f0c1..08cc7fb 100644 --- a/docs/examples/ex_nested_dataclasses.py +++ b/docs/examples/ex_nested_dataclasses.py @@ -11,4 +11,3 @@ class Navbar: navbar = Navbar(button=('https://example.com',)) print(navbar) -#> Navbar(button=NavbarButton(href='https://example.com')) diff --git a/docs/examples/ex_post_init_post_parse.py b/docs/examples/ex_post_init_post_parse.py index d284ad9..40ff3e3 100644 --- a/docs/examples/ex_post_init_post_parse.py +++ b/docs/examples/ex_post_init_post_parse.py @@ -7,18 +7,14 @@ class Birth: month: int day: int - @dataclass class User: birth: Birth def __post_init__(self): print(self.birth) - # > {'year': 1995, 'month': 3, 'day': 2} def __post_init_post_parse__(self): print(self.birth) - # > Birth(year=1995, month=3, day=2) - user = User(**{'birth': {'year': 1995, 'month': 3, 'day': 2}}) diff --git a/docs/examples/ex_secret_types.py b/docs/examples/ex_secret_types.py index 16528be..7509951 100644 --- a/docs/examples/ex_secret_types.py +++ b/docs/examples/ex_secret_types.py @@ -1,5 +1,3 @@ -from typing import List - from pydantic import BaseModel, SecretStr, SecretBytes, ValidationError class SimpleModel(BaseModel): @@ -8,26 +6,13 @@ class SimpleModel(BaseModel): sm = SimpleModel(password='IAmSensitive', password_bytes=b'IAmSensitiveBytes') print(sm) -#> SimpleModel password=SecretStr('**********') password_bytes=SecretBytes(b'**********') print(sm.password.get_secret_value()) -#> IAmSensitive print(sm.password_bytes.get_secret_value()) -#> b'IAmSensitiveBytes' print(sm.password.display()) -#> '**********' print(sm.json()) -#> '{"password": "**********", "password_bytes": "**********"}' - try: - SimpleModel(password=[1,2,3], password_bytes=[1,2,3]) + SimpleModel(password=[1, 2, 3], password_bytes=[1, 2, 3]) except ValidationError as e: print(e) -""" -2 validation error -password - str type expected (type=type_error.str) -password_bytes - byte type expected (type=type_error.bytes) -""" diff --git a/docs/examples/ex_typing.py b/docs/examples/ex_typing.py index 8604c80..8cc66f4 100644 --- a/docs/examples/ex_typing.py +++ b/docs/examples/ex_typing.py @@ -2,7 +2,6 @@ from typing import Dict, FrozenSet, List, Optional, Sequence, Set, Tuple, Union from pydantic import BaseModel - class Model(BaseModel): simple_list: list = None list_of_ints: List[int] = None @@ -24,14 +23,14 @@ class Model(BaseModel): compound: Dict[Union[str, bytes], List[Set[int]]] = None -print(Model(simple_list=['1', '2', '3']).simple_list) # > ['1', '2', '3'] -print(Model(list_of_ints=['1', '2', '3']).list_of_ints) # > [1, 2, 3] +print(Model(simple_list=['1', '2', '3']).simple_list) +print(Model(list_of_ints=['1', '2', '3']).list_of_ints) -print(Model(simple_dict={'a': 1, b'b': 2}).simple_dict) # > {'a': 1, b'b': 2} -print(Model(dict_str_float={'a': 1, b'b': 2}).dict_str_float) # > {'a': 1.0, 'b': 2.0} +print(Model(simple_dict={'a': 1, b'b': 2}).simple_dict) +print(Model(dict_str_float={'a': 1, b'b': 2}).dict_str_float) -print(Model(simple_tuple=[1, 2, 3, 4]).simple_tuple) # > (1, 2, 3, 4) -print(Model(tuple_of_different_types=[4, 3, 2, 1]).tuple_of_different_types) # > (4, 3.0, '2', True) +print(Model(simple_tuple=[1, 2, 3, 4]).simple_tuple) +print(Model(tuple_of_different_types=[4, 3, 2, 1]).tuple_of_different_types) -print(Model(sequence_of_ints=[1, 2, 3, 4]).sequence_of_ints) # > [1, 2, 3, 4] -print(Model(sequence_of_ints=(1, 2, 3, 4)).sequence_of_ints) # > (1, 2, 3, 4) +print(Model(sequence_of_ints=[1, 2, 3, 4]).sequence_of_ints) +print(Model(sequence_of_ints=(1, 2, 3, 4)).sequence_of_ints) diff --git a/docs/examples/example1.py b/docs/examples/example1.py index 585c040..1016b49 100644 --- a/docs/examples/example1.py +++ b/docs/examples/example1.py @@ -15,17 +15,6 @@ external_data = { } user = User(**external_data) print(user.id) -#> 123 print(repr(user.signup_ts)) -#> datetime.datetime(2019, 6, 1, 12, 22) print(user.friends) -#> [1, 2, 3] print(user.dict()) -#> { -#> 'id': 123, -#> 'signup_ts': datetime.datetime(2019, 6, 1, 12, 22), -#> 'friends': [1, 2, 3], -#> 'name': 'John Doe' -#> } -print(user.json()) -#> {"id": 123, "signup_ts": "2019-06-01T12:22:00", ... diff --git a/docs/examples/example2.py b/docs/examples/example2.py index b5c3b69..5b46869 100644 --- a/docs/examples/example2.py +++ b/docs/examples/example2.py @@ -1,3 +1,5 @@ +from example1 import User +# === ignore above from pydantic import ValidationError try: diff --git a/docs/examples/example2_output.json b/docs/examples/example2_output.json deleted file mode 100644 index cd708a5..0000000 --- a/docs/examples/example2_output.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "loc": [ - "id" - ], - "msg": "field required", - "type": "value_error.missing" - }, - { - "loc": [ - "signup_ts" - ], - "msg": "invalid datetime format", - "type": "type_error.datetime" - }, - { - "loc": [ - "friends", - 2 - ], - "msg": "value is not a valid integer", - "type": "type_error.integer" - } -] diff --git a/docs/examples/export_copy.py b/docs/examples/export_copy.py index 408958f..b0bedee 100644 --- a/docs/examples/export_copy.py +++ b/docs/examples/export_copy.py @@ -11,18 +11,9 @@ class FooBarModel(BaseModel): m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123}) print(m.copy(include={'foo', 'bar'})) -#> FooBarModel foo='hello' bar= - print(m.copy(exclude={'foo', 'bar'})) -#> FooBarModel banana=3.14 - print(m.copy(update={'banana': 0})) -#> FooBarModel banana=0 foo='hello' bar= - print(id(m.bar), id(m.copy().bar)) # normal copy gives the same object reference for `bar` -#> 140494497582280 140494497582280 - print(id(m.bar), id(m.copy(deep=True).bar)) # deep copy gives a new object reference for `bar` -#> 140494497582280 140494497582856 diff --git a/docs/examples/export_dict.py b/docs/examples/export_dict.py index 77bea23..5caa318 100644 --- a/docs/examples/export_dict.py +++ b/docs/examples/export_dict.py @@ -10,12 +10,7 @@ class FooBarModel(BaseModel): m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123}) +# returns a dictionary: print(m.dict()) -# (returns a dictionary) -#> {'banana': 3.14, 'foo': 'hello', 'bar': {'whatever': 123}} - print(m.dict(include={'foo', 'bar'})) -#> {'foo': 'hello', 'bar': {'whatever': 123}} - print(m.dict(exclude={'foo', 'bar'})) -#> {'banana': 3.14} diff --git a/docs/examples/export_iterate.py b/docs/examples/export_iterate.py index 9d9dcad..12ec3fd 100644 --- a/docs/examples/export_iterate.py +++ b/docs/examples/export_iterate.py @@ -11,11 +11,6 @@ class FooBarModel(BaseModel): m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123}) print(dict(m)) -#> {'banana': 3.14, 'foo': 'hello', 'bar': } - for name, value in m: print(f'{name}: {value}') -#> banana: 3.14 -#> foo: hello -#> bar: BarModel whatever=123 diff --git a/docs/examples/export_json.py b/docs/examples/export_json.py index 3ca5a63..303d92e 100644 --- a/docs/examples/export_json.py +++ b/docs/examples/export_json.py @@ -12,8 +12,6 @@ class FooBarModel(BaseModel): m = FooBarModel(foo=datetime(2032, 6, 1, 12, 13, 14), bar={'whatever': 123}) print(m.json()) # (returns a str) -#> {"foo": "2032-06-01T12:13:14", "bar": {"whatever": 123}} - class WithCustomEncoders(BaseModel): dt: datetime diff: timedelta @@ -26,4 +24,3 @@ class WithCustomEncoders(BaseModel): m = WithCustomEncoders(dt=datetime(2032, 6, 1), diff=timedelta(hours=100)) print(m.json()) -#> {"dt": 1969660800.0, "diff": "P4DT4H0M0.000000S"} diff --git a/docs/examples/export_pickle.py b/docs/examples/export_pickle.py index 2451bd6..1020cfa 100644 --- a/docs/examples/export_pickle.py +++ b/docs/examples/export_pickle.py @@ -7,12 +7,7 @@ class FooBarModel(BaseModel): m = FooBarModel(a='hello', b=123) print(m) -#> FooBarModel a='hello' b=123 - data = pickle.dumps(m) print(data) -#> b'\x80\x03c...' - m2 = pickle.loads(data) print(m2) -#> FooBarModel a='hello' b=123 diff --git a/docs/examples/field_order.py b/docs/examples/field_order.py index dc07a68..238c477 100644 --- a/docs/examples/field_order.py +++ b/docs/examples/field_order.py @@ -8,15 +8,11 @@ class Model(BaseModel): e: float print(Model.__fields__.keys()) -#> dict_keys(['a', 'c', 'e', 'b', 'd']) m = Model(e=2, a=1) print(m.dict()) -#> {'a': 1, 'c': 'x', 'e': 2.0, 'b': 2, 'd': 'y'} - try: Model(a='x', b='x', c='x', d='x', e='x') except ValidationError as e: - error_logs = [e['loc'] for e in e.errors()] + error_locations = [e['loc'] for e in e.errors()] -print(error_logs) -#> [('a',), ('c',), ('e',), ('b',), ('d',)] +print(error_locations) diff --git a/docs/examples/forward_ref.py b/docs/examples/forward_ref.py index 3ad08d9..c167e26 100644 --- a/docs/examples/forward_ref.py +++ b/docs/examples/forward_ref.py @@ -10,6 +10,4 @@ class Foo(BaseModel): Foo.update_forward_refs() print(Foo()) -#> Foo a=123 b=None print(Foo(b={'a': '321'})) -#> Foo a=123 b= diff --git a/docs/examples/generics-naming.py b/docs/examples/generics-naming.py index 9adb41f..db72045 100644 --- a/docs/examples/generics-naming.py +++ b/docs/examples/generics-naming.py @@ -12,6 +12,4 @@ class Response(GenericModel, Generic[DataT]): return f'{params[0].__name__.title()}Response' print(Response[int](data=1)) -#> IntResponse data=1 print(Response[str](data='a')) -#> StrResponse data='a' diff --git a/docs/examples/generics.py b/docs/examples/generics.py index 4b5a0fb..6ff2d59 100644 --- a/docs/examples/generics.py +++ b/docs/examples/generics.py @@ -3,20 +3,16 @@ from typing import Generic, TypeVar, Optional, List from pydantic import BaseModel, validator, ValidationError from pydantic.generics import GenericModel - DataT = TypeVar('DataT') - class Error(BaseModel): code: int message: str - class DataModel(BaseModel): numbers: List[int] people: List[str] - class Response(GenericModel, Generic[DataT]): data: Optional[DataT] error: Optional[Error] @@ -29,33 +25,15 @@ class Response(GenericModel, Generic[DataT]): raise ValueError('must provide data or error') return v - data = DataModel(numbers=[1, 2, 3], people=[]) error = Error(code=404, message='Not found') print(Response[int](data=1)) -#> Response[int] data=1 error=None print(Response[str](data='value')) -#> Response[str] data='value' error=None print(Response[str](data='value').dict()) -#> {'data': 'value', 'error': None} print(Response[DataModel](data=data).dict()) -#> {'data': {'numbers': [1, 2, 3], 'people': []}, 'error': None} print(Response[DataModel](error=error).dict()) -#> {'data': None, 'error': {'code': 404, 'message': 'Not found'}} - try: Response[int](data='value') except ValidationError as e: print(e) -""" -4 validation errors -data - value is not a valid integer (type=type_error.integer) -data - value is not none (type=type_error.none.allowed) -error - value is not a valid dict (type=type_error.dict) -error - must provide data or error (type=value_error) -""" diff --git a/docs/examples/json_orjson.py b/docs/examples/json_orjson.py index 5fd51a5..173f5ed 100644 --- a/docs/examples/json_orjson.py +++ b/docs/examples/json_orjson.py @@ -15,7 +15,5 @@ class User(BaseModel): json_loads = orjson.loads json_dumps = orjson_dumps - -user = User.parse_raw('{"id": 123, "signup_ts": 1234567890, "name": "John Doe"}') +user = User.parse_raw('{"id":123,"signup_ts":1234567890,"name":"John Doe"}') print(user.json()) -#> {"id":123,"signup_ts":"2009-02-13T23:31:30+00:00","name":"John Doe"} diff --git a/docs/examples/json_ujson.py b/docs/examples/json_ujson.py index 9498294..bfaa35d 100644 --- a/docs/examples/json_ujson.py +++ b/docs/examples/json_ujson.py @@ -10,6 +10,5 @@ class User(BaseModel): class Config: json_loads = ujson.loads -user = User.parse_raw('{"id": 123, "signup_ts": 1234567890, "name": "John Doe"}') +user = User.parse_raw('{"id": 123,"signup_ts":1234567890,"name":"John Doe"}') print(user) -#> User id=123 signup_ts=datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=datetime.timezone.utc) name='John Doe' diff --git a/docs/examples/literal1.py b/docs/examples/literal1.py index 7e94b69..0345ec9 100644 --- a/docs/examples/literal1.py +++ b/docs/examples/literal1.py @@ -11,8 +11,3 @@ try: Pie(flavor='cherry') except ValidationError as e: print(str(e)) -""" -1 validation error -flavor - unexpected value; permitted: 'apple', 'pumpkin' (type=value_error.const; given=cherry; permitted=('apple', 'pumpkin')) -""" diff --git a/docs/examples/literal2.py b/docs/examples/literal2.py index 14b4213..6a8f4d8 100644 --- a/docs/examples/literal2.py +++ b/docs/examples/literal2.py @@ -16,17 +16,8 @@ class Meal(BaseModel): dessert: Union[Cake, IceCream] print(type(Meal(dessert={'kind': 'cake'}).dessert).__name__) -#> Cake print(type(Meal(dessert={'kind': 'icecream'}).dessert).__name__) -#> IceCream try: Meal(dessert={'kind': 'pie'}) except ValidationError as e: print(str(e)) -""" -2 validation errors -dessert -> kind - unexpected value; permitted: 'cake' (type=value_error.const; given=pie; permitted=('cake',)) -dessert -> kind - unexpected value; permitted: 'icecream' (type=value_error.const; given=pie; permitted=('icecream',)) -""" diff --git a/docs/examples/literal3.py b/docs/examples/literal3.py index c65b210..892d8ab 100644 --- a/docs/examples/literal3.py +++ b/docs/examples/literal3.py @@ -21,10 +21,6 @@ class Meal(BaseModel): dessert: Union[ApplePie, PumpkinPie, Pie, Dessert] print(type(Meal(dessert={'kind': 'pie', 'flavor': 'apple'}).dessert).__name__) -#> ApplePie print(type(Meal(dessert={'kind': 'pie', 'flavor': 'pumpkin'}).dessert).__name__) -#> PumpkinPie print(type(Meal(dessert={'kind': 'pie'}).dessert).__name__) -#> Pie print(type(Meal(dessert={'kind': 'cake'}).dessert).__name__) -#> Dessert diff --git a/docs/examples/mutation.py b/docs/examples/mutation.py index 0caed42..2ae3817 100644 --- a/docs/examples/mutation.py +++ b/docs/examples/mutation.py @@ -1,6 +1,5 @@ from pydantic import BaseModel - class FooBarModel(BaseModel): a: str b: dict @@ -8,7 +7,6 @@ class FooBarModel(BaseModel): class Config: allow_mutation = False - foobar = FooBarModel(a='hello', b={'apple': 'pear'}) try: @@ -18,11 +16,6 @@ except TypeError as e: # > "FooBarModel" is immutable and does not support item assignment print(foobar.a) -#> hello - print(foobar.b) -#> {'apple': 'pear'} - foobar.b['apple'] = 'grape' print(foobar.b) -#> {'apple': 'grape'} diff --git a/docs/examples/mypy.py b/docs/examples/mypy.py index c9cf961..af154b5 100644 --- a/docs/examples/mypy.py +++ b/docs/examples/mypy.py @@ -11,7 +11,5 @@ class Model(BaseModel): m = Model(age=42, list_of_ints=[1, '2', b'3']) print(m.age) -#> 42 - Model() # will raise a validation error for age and list_of_ints diff --git a/docs/examples/orm_mode.py b/docs/examples/orm_mode.py index 2e54c80..8b76ee0 100644 --- a/docs/examples/orm_mode.py +++ b/docs/examples/orm_mode.py @@ -29,10 +29,5 @@ co_orm = CompanyOrm( domains=['example.com', 'foobar.com'] ) print(co_orm) -#> <__main__.CompanyOrm object at 0x7ff4bf918278> co_model = CompanyModel.from_orm(co_orm) print(co_model) -#> CompanyModel id=123 -#> public_key='foobar' -#> name='Testing' -#> domains=['example.com', 'foobar.com'] diff --git a/docs/examples/orm_mode_recursive.py b/docs/examples/orm_mode_recursive.py index 40f9023..47a16eb 100644 --- a/docs/examples/orm_mode_recursive.py +++ b/docs/examples/orm_mode_recursive.py @@ -32,9 +32,3 @@ orion = PetCls(name='Orion', species='cat') anna = PersonCls(name='Anna', age=20, pets=[bones, orion]) anna_model = Person.from_orm(anna) print(anna_model) -#> Person name='Anna' -#> pets=[ -#> , -#> -#> ] -#> age=20.0 diff --git a/docs/examples/parse.py b/docs/examples/parse.py index a643c41..bba72c9 100644 --- a/docs/examples/parse.py +++ b/docs/examples/parse.py @@ -9,20 +9,21 @@ class User(BaseModel): m = User.parse_obj({'id': 123, 'name': 'James'}) print(m) -#> User id=123 name='James' signup_ts=None try: User.parse_obj(['not', 'a', 'dict']) except ValidationError as e: print(e) -#> error validating input -#> User expected dict not list (error_type=TypeError) -m = User.parse_raw('{"id": 123, "name": "James"}') # assumes json as no content type passed +# assumes json as no content type passed +m = User.parse_raw('{"id": 123, "name": "James"}') print(m) -#> User id=123 name='James' signup_ts=None -pickle_data = pickle.dumps({'id': 123, 'name': 'James', 'signup_ts': datetime(2017, 7, 14)}) -m = User.parse_raw(pickle_data, content_type='application/pickle', allow_pickle=True) +pickle_data = pickle.dumps({ + 'id': 123, + 'name': 'James', + 'signup_ts': datetime(2017, 7, 14) +}) +m = User.parse_raw(pickle_data, content_type='application/pickle', + allow_pickle=True) print(m) -#> User id=123 name='James' signup_ts=datetime.datetime(2017, 7, 14, 0, 0) diff --git a/docs/examples/postponed_annotations.py b/docs/examples/postponed_annotations.py index a98dcb9..99aa7c0 100644 --- a/docs/examples/postponed_annotations.py +++ b/docs/examples/postponed_annotations.py @@ -6,4 +6,3 @@ class Model(BaseModel): a: List[int] print(Model(a=('1', 2, 3))) -#> Model a=[1, 2, 3] diff --git a/docs/examples/postponed_broken.py b/docs/examples/postponed_broken.py index 67ea4a8..d3d68d4 100644 --- a/docs/examples/postponed_broken.py +++ b/docs/examples/postponed_broken.py @@ -2,7 +2,9 @@ from __future__ import annotations from pydantic import BaseModel def this_is_broken(): - from typing import List # <-- List is defined inside the function so is not in the module's global scope + # List is defined inside the function so is not in the module's + # global scope! + from typing import List class Model(BaseModel): a: List[int] print(Model(a=(1, 2))) diff --git a/docs/examples/recursive.py b/docs/examples/recursive.py index 6cf40fb..117bb00 100644 --- a/docs/examples/recursive.py +++ b/docs/examples/recursive.py @@ -15,13 +15,4 @@ class Spam(BaseModel): m = Spam(foo={'count': 4}, bars=[{'apple': 'x1'}, {'apple': 'x2'}]) print(m) -#> Spam foo= -#> bars=[, ] print(m.dict()) -#> { -#> 'foo': {'count': 4, 'size': None}, -#> 'bars': [ -#> {'apple': 'x1', 'banana': 'y'}, -#> {'apple': 'x2', 'banana': 'y'} -#> ] -#> } diff --git a/docs/examples/schema1.json b/docs/examples/schema1.json deleted file mode 100644 index 50d1fc1..0000000 --- a/docs/examples/schema1.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "title": "Main", - "description": "This is the description of the main model", - "type": "object", - "properties": { - "foo_bar": { - "$ref": "#/definitions/FooBar" - }, - "Gender": { - "title": "Gender", - "enum": [ - "male", - "female", - "other", - "not_given" - ], - "type": "string" - }, - "snap": { - "title": "The Snap", - "description": "this is the value of snap", - "default": 42, - "exclusiveMinimum": 30, - "exclusiveMaximum": 50, - "type": "integer" - } - }, - "required": [ - "foo_bar" - ], - "definitions": { - "FooBar": { - "title": "FooBar", - "type": "object", - "properties": { - "count": { - "title": "Count", - "type": "integer" - }, - "size": { - "title": "Size", - "type": "number" - } - }, - "required": [ - "count" - ] - } - } -} diff --git a/docs/examples/schema1.py b/docs/examples/schema1.py index a96762b..1c66563 100644 --- a/docs/examples/schema1.py +++ b/docs/examples/schema1.py @@ -28,11 +28,5 @@ class MainModel(BaseModel): class Config: title = 'Main' -print(MainModel.schema()) -#> { -#> 'type': 'object', -#> 'title': 'Main', -#> 'properties': { -#> 'foo_bar': { -#> ... +# this is equivilant of json.dumps(MainModel.schema(), indent=2): print(MainModel.schema_json(indent=2)) diff --git a/docs/examples/schema2.json b/docs/examples/schema2.json deleted file mode 100644 index 8de2dfb..0000000 --- a/docs/examples/schema2.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "title": "My Schema", - "definitions": { - "Foo": { - "title": "Foo", - "type": "object", - "properties": { - "a": { - "title": "A", - "type": "string" - } - } - }, - "Model": { - "title": "Model", - "type": "object", - "properties": { - "b": { - "$ref": "#/definitions/Foo" - } - }, - "required": [ - "b" - ] - }, - "Bar": { - "title": "Bar", - "type": "object", - "properties": { - "c": { - "title": "C", - "type": "integer" - } - }, - "required": [ - "c" - ] - } - } -} diff --git a/docs/examples/schema2.py b/docs/examples/schema2.py index 805c58b..263658f 100644 --- a/docs/examples/schema2.py +++ b/docs/examples/schema2.py @@ -2,25 +2,15 @@ import json from pydantic import BaseModel from pydantic.schema import schema - class Foo(BaseModel): a: str = None - class Model(BaseModel): b: Foo - class Bar(BaseModel): c: int - top_level_schema = schema([Model, Bar], title='My Schema') print(json.dumps(top_level_schema, indent=2)) -#> { -#> "title": "My Schema", -#> "definitions": { -#> "Foo": { -#> "title": "Foo", -#> ... diff --git a/docs/examples/schema3.json b/docs/examples/schema3.json deleted file mode 100644 index aa23845..0000000 --- a/docs/examples/schema3.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "definitions": { - "Foo": { - "title": "Foo", - "type": "object", - "properties": { - "a": { - "title": "A", - "type": "integer" - } - }, - "required": [ - "a" - ] - }, - "Model": { - "title": "Model", - "type": "object", - "properties": { - "a": { - "$ref": "#/components/schemas/Foo" - } - }, - "required": [ - "a" - ] - } - } -} diff --git a/docs/examples/schema3.py b/docs/examples/schema3.py index 7889b05..6cc3287 100644 --- a/docs/examples/schema3.py +++ b/docs/examples/schema3.py @@ -8,13 +8,7 @@ class Foo(BaseModel): class Model(BaseModel): a: Foo - -top_level_schema = schema([Model], ref_prefix='#/components/schemas/') # Default location for OpenAPI +# Default location for OpenAPI +top_level_schema = schema([Model], ref_prefix='#/components/schemas/') print(json.dumps(top_level_schema, indent=2)) -#> { -#> "definitions": { -#> "Foo": { -#> "title": "Foo", -#> "type": "object", -#> ... diff --git a/docs/examples/schema4.json b/docs/examples/schema4.json deleted file mode 100644 index 0d806e7..0000000 --- a/docs/examples/schema4.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "title": "Person", - "type": "object", - "properties": { - "name": { - "title": "Name", - "type": "string" - }, - "age": { - "title": "Age", - "type": "integer" - } - }, - "required": [ - "name", - "age" - ], - "examples": [ - { - "name": "John Doe", - "age": 25 - } - ] -} \ No newline at end of file diff --git a/docs/examples/schema4.py b/docs/examples/schema4.py index 6d5c53e..7b20a28 100644 --- a/docs/examples/schema4.py +++ b/docs/examples/schema4.py @@ -1,6 +1,5 @@ from pydantic import BaseModel - class Person(BaseModel): name: str age: int @@ -15,12 +14,4 @@ class Person(BaseModel): ] } - -print(Person.schema()) -#> {'title': 'Person', -#> 'type': 'object', -#> 'properties': {'name': {'title': 'Name', 'type': 'string'}, -#> 'age': {'title': 'Age', 'type': 'integer'}}, -#> 'required': ['name', 'age'], -#> 'examples': [{'name': 'John Doe', 'age': 25}]} print(Person.schema_json(indent=2)) diff --git a/docs/examples/self_referencing_annotations.py b/docs/examples/self_referencing_annotations.py index 3c1828b..d71710c 100644 --- a/docs/examples/self_referencing_annotations.py +++ b/docs/examples/self_referencing_annotations.py @@ -9,6 +9,4 @@ class Foo(BaseModel): Foo.update_forward_refs() print(Foo()) -#> Foo a=123 sibling=None print(Foo(sibling={'a': '321'})) -#> Foo a=123 sibling= diff --git a/docs/examples/self_referencing_string.py b/docs/examples/self_referencing_string.py index 18a6dcd..5ca1cfd 100644 --- a/docs/examples/self_referencing_string.py +++ b/docs/examples/self_referencing_string.py @@ -8,6 +8,4 @@ class Foo(BaseModel): Foo.update_forward_refs() print(Foo()) -#> Foo a=123 sibling=None print(Foo(sibling={'a': '321'})) -#> Foo a=123 sibling= diff --git a/docs/examples/settings.py b/docs/examples/settings.py index e020114..843940f 100644 --- a/docs/examples/settings.py +++ b/docs/examples/settings.py @@ -1,7 +1,8 @@ from typing import Set -from devtools import debug -from pydantic import BaseModel, BaseSettings, PyObject, RedisDsn, PostgresDsn, Field +from pydantic import ( + BaseModel, BaseSettings, PyObject, RedisDsn, PostgresDsn, Field +) class SubModel(BaseModel): foo = 'bar' @@ -35,23 +36,4 @@ class Settings(BaseSettings): } } -""" -When calling with -my_auth_key=a \ -MY_API_KEY=b \ -my_prefix_domains='["foo.com", "bar.com"]' \ -python docs/examples/settings.py -""" -debug(Settings().dict()) -""" -docs/examples/settings.py:45 - Settings().dict(): { - 'auth_key': 'a', - 'api_key': 'b', - 'redis_dsn': , - 'pg_dsn': , - 'special_function': , - 'domains': {'bar.com', 'foo.com'}, - 'more_settings': {'foo': 'bar', 'apple': 1}, - } (dict) len=7 -""" +print(Settings().dict()) diff --git a/docs/examples/settings_case_sensitive.py b/docs/examples/settings_case_sensitive.py index 5030704..b043b7d 100644 --- a/docs/examples/settings_case_sensitive.py +++ b/docs/examples/settings_case_sensitive.py @@ -1,6 +1,5 @@ from pydantic import BaseSettings - class Settings(BaseSettings): redis_host = 'localhost' diff --git a/docs/examples/strict_types.py b/docs/examples/strict_types.py index 2020bc7..ce853da 100644 --- a/docs/examples/strict_types.py +++ b/docs/examples/strict_types.py @@ -1,5 +1,6 @@ -from pydantic import BaseModel, confloat, StrictBool, StrictInt, ValidationError - +from pydantic import ( + BaseModel, confloat, StrictBool, StrictInt, ValidationError +) class StrictIntModel(BaseModel): strict_int: StrictInt @@ -8,11 +9,6 @@ try: StrictIntModel(strict_int=3.14159) except ValidationError as e: print(e) -""" -1 validation error for StrictIntModel -strict_int - value is not a valid integer (type=type_error.integer) -""" class ConstrainedFloatModel(BaseModel): constrained_float: confloat(strict=True, ge=0.0) @@ -21,21 +17,11 @@ try: ConstrainedFloatModel(constrained_float=3) except ValidationError as e: print(e) -""" -1 validation error for ConstrainedFloatModel -constrained_float - value is not a valid float (type=type_error.float) -""" try: ConstrainedFloatModel(constrained_float=-1.23) except ValidationError as e: print(e) -""" -1 validation error for ConstrainedFloatModel -constrained_float - ensure this value is greater than or equal to 0.0 (type=value_error.number.not_ge; limit_value=0.0) -""" class StrictBoolModel(BaseModel): strict_bool: StrictBool @@ -44,8 +30,3 @@ try: StrictBoolModel(strict_bool='False') except ValidationError as e: print(str(e)) -""" -1 validation error -strict_bool - value is not a valid boolean (type=value_error.strictbool) -""" diff --git a/docs/examples/type_type.py b/docs/examples/type_type.py index 985ab6b..b2a1dc9 100644 --- a/docs/examples/type_type.py +++ b/docs/examples/type_type.py @@ -15,15 +15,9 @@ class Other: class SimpleModel(BaseModel): just_subclasses: Type[Foo] - SimpleModel(just_subclasses=Foo) SimpleModel(just_subclasses=Bar) try: SimpleModel(just_subclasses=Other) except ValidationError as e: print(e) -""" -1 validation error -just_subclasses - subclass of Foo expected (type=type_error.class) -""" diff --git a/docs/examples/union_type_correct.py b/docs/examples/union_type_correct.py index fb8b163..77c4601 100644 --- a/docs/examples/union_type_correct.py +++ b/docs/examples/union_type_correct.py @@ -2,17 +2,12 @@ from uuid import UUID from typing import Union from pydantic import BaseModel - class User(BaseModel): id: Union[UUID, int, str] name: str - user_03_uuid = UUID('cf57432e-809e-4353-adbd-9d5c0d733868') user_03 = User(id=user_03_uuid, name='John Doe') print(user_03) -#> User id=UUID('cf57432e-809e-4353-adbd-9d5c0d733868') name='John Doe' print(user_03.id) -#> cf57432e-809e-4353-adbd-9d5c0d733868 print(user_03_uuid.int) -#> 275603287559914445491632874575877060712 diff --git a/docs/examples/union_type_incorrect.py b/docs/examples/union_type_incorrect.py index 853cd69..c0454c8 100644 --- a/docs/examples/union_type_incorrect.py +++ b/docs/examples/union_type_incorrect.py @@ -2,29 +2,18 @@ from uuid import UUID from typing import Union from pydantic import BaseModel - class User(BaseModel): id: Union[int, str, UUID] name: str - user_01 = User(id=123, name='John Doe') print(user_01) -#> User id=123 name='John Doe' print(user_01.id) -#> 123 - user_02 = User(id='1234', name='John Doe') print(user_02) -#> User id=1234 name='John Doe' print(user_02.id) -#> 1234 - user_03_uuid = UUID('cf57432e-809e-4353-adbd-9d5c0d733868') user_03 = User(id=user_03_uuid, name='John Doe') print(user_03) -#> User id=275603287559914445491632874575877060712 name='John Doe' print(user_03.id) -#> 275603287559914445491632874575877060712 print(user_03_uuid.int) -#> 275603287559914445491632874575877060712 diff --git a/docs/examples/url_properties.py b/docs/examples/url_properties.py index 9f5d97c..8e0f8ae 100644 --- a/docs/examples/url_properties.py +++ b/docs/examples/url_properties.py @@ -7,18 +7,10 @@ m = MyModel(url='http://www.example.com') # the repr() method for a url will display all properties of the url print(repr(m.url)) -#> tld='com' host_type='domain')> - print(m.url.scheme) -#> http print(m.url.host) -#> www.example.com print(m.url.host_type) -#> domain print(m.url.port) -#> None - class MyDatabaseModel(BaseModel): db: PostgresDsn @@ -29,14 +21,9 @@ class MyDatabaseModel(BaseModel): m = MyDatabaseModel(db='postgres://user:pass@localhost:5432/foobar') print(m.db) -#> postgres://user:pass@localhost:5432/foobar try: MyDatabaseModel(db='postgres://user:pass@localhost:5432') except ValidationError as e: print(e) -""" -1 validation error for MyDatabaseModel -db - database must be provided (type=assertion_error) -""" + diff --git a/docs/examples/url_punycode.py b/docs/examples/url_punycode.py index 2507d18..bee5fec 100644 --- a/docs/examples/url_punycode.py +++ b/docs/examples/url_punycode.py @@ -5,12 +5,7 @@ class MyModel(BaseModel): m1 = MyModel(url='http://puny£code.com') print(m1.url) -#> http://xn--punycode-eja.com print(m1.url.host_type) -#> int_domain - m2 = MyModel(url='https://www.аррӏе.com/') print(m2.url) -#> https://www.xn--80ak6aa92e.com/ print(m2.url.host_type) -#> int_domain diff --git a/docs/examples/urls.py b/docs/examples/urls.py index 9a96935..0158552 100644 --- a/docs/examples/urls.py +++ b/docs/examples/urls.py @@ -5,25 +5,12 @@ class MyModel(BaseModel): m = MyModel(url='http://www.example.com') print(m.url) -#> http://www.example.com - try: MyModel(url='ftp://invalid.url') except ValidationError as e: print(e) -""" -1 validation error for MyModel -url - URL scheme not permitted (type=value_error.url.scheme; - allowed_schemes={'http', 'https'}) -""" try: MyModel(url='not a url') except ValidationError as e: print(e) -""" -1 validation error for MyModel -url - invalid or missing URL scheme (type=value_error.url.scheme) -""" diff --git a/docs/examples/validators_always.py b/docs/examples/validators_always.py index 8a747de..838dc60 100644 --- a/docs/examples/validators_always.py +++ b/docs/examples/validators_always.py @@ -2,7 +2,6 @@ from datetime import datetime from pydantic import BaseModel, validator - class DemoModel(BaseModel): ts: datetime = None @@ -10,9 +9,5 @@ class DemoModel(BaseModel): def set_ts_now(cls, v): return v or datetime.now() - print(DemoModel()) -#> DemoModel ts=datetime.datetime(2017, 11, 8, 13, 59, 11, 723629) - print(DemoModel(ts='2017-11-08T14:00')) -#> DemoModel ts=datetime.datetime(2017, 11, 8, 14, 0) diff --git a/docs/examples/validators_dataclass.py b/docs/examples/validators_dataclass.py index 4aa6ca0..389a00b 100644 --- a/docs/examples/validators_dataclass.py +++ b/docs/examples/validators_dataclass.py @@ -3,7 +3,6 @@ from datetime import datetime from pydantic import validator from pydantic.dataclasses import dataclass - @dataclass class DemoDataclass: ts: datetime = None @@ -12,9 +11,5 @@ class DemoDataclass: def set_ts_now(cls, v): return v or datetime.now() - print(DemoDataclass()) -#> DemoDataclass(ts=datetime.datetime(2019, 4, 2, 18, 1, 46, 66149)) - print(DemoDataclass(ts='2017-11-08T14:00')) -#> DemoDataclass ts=datetime.datetime(2017, 11, 8, 14, 0) diff --git a/docs/examples/validators_pre_item.py b/docs/examples/validators_pre_item.py index 654b8a5..207e042 100644 --- a/docs/examples/validators_pre_item.py +++ b/docs/examples/validators_pre_item.py @@ -31,28 +31,15 @@ class DemoModel(BaseModel): return v print(DemoModel(square_numbers=[1, 4, 9])) -#> DemoModel square_numbers=[1, 4, 9] cube_numbers=[] print(DemoModel(square_numbers='1|4|16')) -#> DemoModel square_numbers=[1, 4, 16] cube_numbers=[] print(DemoModel(square_numbers=[16], cube_numbers=[8, 27])) -#> DemoModel square_numbers=[16] cube_numbers=[8, 27] - try: DemoModel(square_numbers=[1, 4, 2]) except ValidationError as e: print(e) -""" -1 validation error for DemoModel -square_numbers -> 2 - 2 is not a square number (type=assertion_error) -""" try: DemoModel(cube_numbers=[27, 27]) except ValidationError as e: print(e) -""" -1 validation error for DemoModel -cube_numbers - sum of numbers greater than 42 (type=value_error) -""" + diff --git a/docs/examples/validators_root.py b/docs/examples/validators_root.py index 041d023..afd829c 100644 --- a/docs/examples/validators_root.py +++ b/docs/examples/validators_root.py @@ -18,24 +18,13 @@ class UserModel(BaseModel): return values print(UserModel(username='scolvin', password1='zxcvbn', password2='zxcvbn')) -#> UserModel username='scolvin' password1='zxcvbn' password2='zxcvbn' - try: UserModel(username='scolvin', password1='zxcvbn', password2='zxcvbn2') except ValidationError as e: print(e) -""" -1 validation error for UserModel -__root__ - passwords do not match (type=value_error) -""" try: - UserModel(username='scolvin', password1='zxcvbn', password2='zxcvbn', card_number='1234') + UserModel(username='scolvin', password1='zxcvbn', password2='zxcvbn', + card_number='1234') except ValidationError as e: print(e) -""" -1 validation error for UserModel -__root__ - card_number should not be included (type=assertion_error) -""" diff --git a/docs/examples/validators_simple.py b/docs/examples/validators_simple.py index 8d92bd6..247b7e1 100644 --- a/docs/examples/validators_simple.py +++ b/docs/examples/validators_simple.py @@ -23,17 +23,11 @@ class UserModel(BaseModel): assert v.isalpha(), 'must be alphanumeric' return v -print(UserModel(name='samuel colvin', username='scolvin', password1='zxcvbn', password2='zxcvbn')) -#> UserModel name='Samuel Colvin' username='scolvin' password1='zxcvbn' password2='zxcvbn' +print(UserModel(name='samuel colvin', username='scolvin', password1='zxcvbn', + password2='zxcvbn')) try: - UserModel(name='samuel', username='scolvin', password1='zxcvbn', password2='zxcvbn2') + UserModel(name='samuel', username='scolvin', password1='zxcvbn', + password2='zxcvbn2') except ValidationError as e: print(e) -""" -2 validation errors for UserModel -name - must contain a space (type=value_error) -password2 - passwords do not match (type=value_error) -""" diff --git a/docs/index.md b/docs/index.md index d7bb34c..1bb2b8a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,7 +5,7 @@ [![downloads](https://img.shields.io/pypi/dm/pydantic.svg)](https://pypistats.org/packages/pydantic) [![license](https://img.shields.io/github/license/samuelcolvin/pydantic.svg)](https://github.com/samuelcolvin/pydantic/blob/master/LICENSE) -{!./.version.md!} +{!.version.md!} !!! note These docs refer to Version 1 of *pydantic* which is as-yet unreleased. **v0.32** docs are available @@ -25,7 +25,7 @@ There's also support for an extension to [dataclasses](usage/dataclasses.md) whe ## Example ```py -{!./examples/example1.py!} +{!.tmp_examples/example1.py!} ``` _(This script is complete, it should run "as is")_ @@ -42,11 +42,11 @@ What's going on here: If validation fails pydantic will raise an error with a breakdown of what was wrong: ```py -{!./examples/example2.py!} +{!.tmp_examples/example2.py!} ``` outputs: ```json -{!./examples/example2_output.json!} +{!.tmp_examples/example2.json!} ``` ## Rationale @@ -119,5 +119,5 @@ For a more comprehensive list of open-source projects using *pydantic* see the [list of dependents on github](https://github.com/samuelcolvin/pydantic/network/dependents). diff --git a/docs/requirements.txt b/docs/requirements.txt index a006354..0bd47ea 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,6 @@ mkdocs==1.0.4 mkdocs-material==4.4.3 markdown-include==0.5.1 +sqlalchemy # pyup: ignore +orjson # pyup: ignore +ujson # pyup: ignore diff --git a/docs/usage/dataclasses.md b/docs/usage/dataclasses.md index d43c7db..1c3d76b 100644 --- a/docs/usage/dataclasses.md +++ b/docs/usage/dataclasses.md @@ -4,7 +4,7 @@ If you don't want to use pydantic's `BaseModel` you can instead get the same dat Dataclasses work in python 3.6 using the [dataclasses backport package](https://github.com/ericvsmith/dataclasses). ```py -{!./examples/ex_dataclasses.py!} +{!.tmp_examples/ex_dataclasses.py!} ``` _(This script is complete, it should run "as is")_ @@ -36,7 +36,7 @@ For more information about combining validators with dataclasses, see Nested dataclasses are supported both in dataclasses and normal models. ```py -{!./examples/ex_nested_dataclasses.py!} +{!.tmp_examples/ex_nested_dataclasses.py!} ``` _(This script is complete, it should run "as is")_ @@ -49,7 +49,7 @@ with the help of `__post_init_post_parse__`. This is not the same as `__post_ini code *before* validation. ```py -{!./examples/ex_post_init_post_parse.py!} +{!.tmp_examples/ex_post_init_post_parse.py!} ``` _(This script is complete, it should run "as is")_ @@ -57,6 +57,6 @@ Since version **v1.0**, any fields annotated with `dataclasses.InitVar` are pass `__post_init_post_parse__`. ```py -{!./examples/ex_post_init_post_parse_initvars.py!} +{!.tmp_examples/ex_post_init_post_parse_initvars.py!} ``` _(This script is complete, it should run "as is")_ diff --git a/docs/usage/exporting_models.md b/docs/usage/exporting_models.md index d72c07d..10a386e 100644 --- a/docs/usage/exporting_models.md +++ b/docs/usage/exporting_models.md @@ -16,7 +16,7 @@ Arguments: Example: ```py -{!./examples/export_dict.py!} +{!.tmp_examples/export_dict.py!} ``` _(This script is complete, it should run "as is")_ @@ -29,7 +29,7 @@ returned, so sub-models will not be converted to dictionaries. Example: ```py -{!./examples/export_iterate.py!} +{!.tmp_examples/export_iterate.py!} ``` _(This script is complete, it should run "as is")_ @@ -47,7 +47,7 @@ Arguments: Example: ```py -{!./examples/export_copy.py!} +{!.tmp_examples/export_copy.py!} ``` _(This script is complete, it should run "as is")_ @@ -74,7 +74,7 @@ Arguments: Example: ```py -{!./examples/export_json.py!} +{!.tmp_examples/export_json.py!} ``` _(This script is complete, it should run "as is")_ @@ -89,7 +89,7 @@ and decoding. Using the same plumbing as `copy()`, *pydantic* models support efficient pickling and unpickling. ```py -{!./examples/export_pickle.py!} +{!.tmp_examples/export_pickle.py!} ``` _(This script is complete, it should run "as is")_ @@ -99,14 +99,14 @@ The `dict`, `json`, and `copy` methods support `include` and `exclude` arguments sets or dictionaries. This allows nested selection of which fields to export: ```py -{!./examples/advanced_exclude1.py!} +{!.tmp_examples/advanced_exclude1.py!} ``` The ellipsis (``...``) indicates that we want to exclude or include an entire key, just as if we included it in a set. Of course, the same can be done at any depth level: ```py -{!./examples/advanced_exclude2.py!} +{!.tmp_examples/advanced_exclude2.py!} ``` The same holds for the `json` and `copy` methods. @@ -118,7 +118,7 @@ To improve the performance of encoding and decoding JSON, alternative JSON imple `json_loads` and `json_dumps` properties of `Config`. ```py -{!./examples/json_ujson.py!} +{!.tmp_examples/json_ujson.py!} ``` _(This script is complete, it should run "as is")_ @@ -127,7 +127,7 @@ not accept a `default` fallback function argument. To do this, you may use anoth [orjson](https://github.com/ijl/orjson). ```py -{!./examples/json_orjson.py!} +{!.tmp_examples/json_orjson.py!} ``` _(This script is complete, it should run "as is")_ diff --git a/docs/usage/model_config.md b/docs/usage/model_config.md index 88a3c58..1c43503 100644 --- a/docs/usage/model_config.md +++ b/docs/usage/model_config.md @@ -78,14 +78,14 @@ Options: : a `dict` used to customise the way types are encoded to JSON; see [JSON Serialisation](exporting_models.md#modeljson) ```py -{!./examples/config.py!} +{!.tmp_examples/config.py!} ``` _(This script is complete, it should run "as is")_ Similarly, if using the `@dataclass` decorator: ```py -{!./examples/ex_dataclasses_config.py!} +{!.tmp_examples/ex_dataclasses_config.py!} ``` _(This script is complete, it should run "as is")_ @@ -95,6 +95,6 @@ If data source field names do not match your code style (e. g. CamelCase fields) you can automatically generate aliases using `alias_generator`: ```py -{!./examples/alias_generator_config.py!} +{!.tmp_examples/alias_generator_config.py!} ``` _(This script is complete, it should run "as is")_ diff --git a/docs/usage/models.md b/docs/usage/models.md index 0fb2059..02e9e6e 100644 --- a/docs/usage/models.md +++ b/docs/usage/models.md @@ -106,7 +106,7 @@ Models possess the following methods and attributes: More complex hierarchical data structures can be defined using models themselves as types in annotations. ```py -{!./examples/recursive.py!} +{!.tmp_examples/recursive.py!} ``` _(This script is complete, it should run "as is")_ @@ -123,7 +123,7 @@ To do this: The example here uses SQLAlchemy, but the same approach should work for any ORM. ```py -{!./examples/orm_mode.py!} +{!.tmp_examples/orm_mode.py!} ``` _(This script is complete, it should run "as is")_ @@ -132,7 +132,7 @@ ORM instances will be parsed with `from_orm` recursively as well as at the top l Here a vanilla class is used to demonstrate the principle, but any ORM class could be used instead. ```py -{!./examples/orm_mode_recursive.py!} +{!.tmp_examples/orm_mode_recursive.py!} ``` _(This script is complete, it should run "as is")_ @@ -186,7 +186,7 @@ Each error object contains: As a demonstration: ```py -{!./examples/errors1.py!} +{!.tmp_examples/errors1.py!} ``` _(This script is complete, it should run "as is". `json()` has `indent=2` set by default, but I've tweaked the JSON here and below to make it slightly more concise.)_ @@ -198,14 +198,14 @@ In your custom data types or validators you should use `ValueError`, `TypeError` See [validators](validators.md) for more details on use of the `@validator` decorator. ```py -{!./examples/errors2.py!} +{!.tmp_examples/errors2.py!} ``` _(This script is complete, it should run "as is")_ You can also define your own error classes, which can specify a custom error code, message template, and context: ```py -{!./examples/errors3.py!} +{!.tmp_examples/errors3.py!} ``` _(This script is complete, it should run "as is")_ @@ -221,7 +221,7 @@ _(This script is complete, it should run "as is")_ it is inferred from the file's extension. ```py -{!./examples/parse.py!} +{!.tmp_examples/parse.py!} ``` _(This script is complete, it should run "as is")_ @@ -254,7 +254,7 @@ In order to declare a generic model, you perform the following steps: Here is an example using `GenericModel` to create an easily-reused HTTP response payload wrapper: ```py -{!./examples/generics.py!} +{!.tmp_examples/generics.py!} ``` _(This script is complete, it should run "as is")_ @@ -272,7 +272,7 @@ you would expect mypy to provide if you were to declare the type without using ` If the name of the concrete subclasses is important, you can also override the default behavior: ```py -{!./examples/generics-naming.py!} +{!.tmp_examples/generics-naming.py!} ``` _(This script is complete, it should run "as is")_ @@ -282,7 +282,7 @@ There are some occasions where the shape of a model is not known until runtime. the `create_model` method to allow models to be created on the fly. ```py -{!./examples/dynamic_model_creation.py!} +{!.tmp_examples/dynamic_model_creation.py!} ``` Here `StaticFoobarModel` and `DynamicFoobarModel` are identical. @@ -292,7 +292,7 @@ special key word arguments `__config__` and `__base__` can be used to customise extending a base model with extra fields. ```py -{!./examples/dynamic_inheritance.py!} +{!.tmp_examples/dynamic_inheritance.py!} ``` ## Custom Root Types @@ -305,7 +305,7 @@ The root value can be passed to model `__init__` via the `__root__` keyword argu the first and only argument to `parse_obj`. ```py -{!examples/custom_root_field.py!} +{!.tmp_examples/custom_root_field.py!} ``` ## Faux Immutability @@ -318,7 +318,7 @@ values of instance attributes will raise errors. See [model config](model_config modify a so-called "immutable" object. ```py -{!./examples/mutation.py!} +{!.tmp_examples/mutation.py!} ``` Trying to change `a` caused an error, and `a` remains unchanged. However, the dict `b` is mutable, and the @@ -330,7 +330,7 @@ Pydantic models can be used alongside Python's [Abstract Base Classes](https://docs.python.org/3/library/abc.html) (ABCs). ```py -{!./examples/ex_abc.py!} +{!.tmp_examples/ex_abc.py!} ``` _(This script is complete, it should run "as is")_ @@ -348,7 +348,7 @@ As of **v1.0** all fields with annotations (whether annotation-only or with a de all fields without an annotation. Within their respective groups, fields remain in the order they were defined. ```py -{!./examples/field_order.py!} +{!.tmp_examples/field_order.py!} ``` _(This script is complete, it should run "as is")_ @@ -382,7 +382,7 @@ and in some cases this may result in a loss of information. For example: ```py -{!./examples/data_conversion.py!} +{!.tmp_examples/data_conversion.py!} ``` _(This script is complete, it should run "as is")_ diff --git a/docs/usage/mypy.md b/docs/usage/mypy.md index 7f5ace1..355b8be 100644 --- a/docs/usage/mypy.md +++ b/docs/usage/mypy.md @@ -2,7 +2,7 @@ Pydantic works with [mypy](http://mypy-lang.org/) provided you use the annotatio required fields: ```py -{!./examples/mypy.py!} +{!.tmp_examples/mypy.py!} ``` _(This script is complete, it should run "as is")_ diff --git a/docs/usage/postponed_annotations.md b/docs/usage/postponed_annotations.md index 885345b..19b3edb 100644 --- a/docs/usage/postponed_annotations.md +++ b/docs/usage/postponed_annotations.md @@ -5,7 +5,7 @@ Postponed annotations (as described in [PEP563](https://www.python.org/dev/peps/ "just work". ```py -{!./examples/postponed_annotations.py!} +{!.tmp_examples/postponed_annotations.py!} ``` _(This script is complete, it should run "as is")_ @@ -20,7 +20,7 @@ For example, this happens whenever a model references itself as a field type. When this happens, you'll need to call `update_forward_refs` after the model has been created before it can be used: ```py -{!./examples/forward_ref.py!} +{!.tmp_examples/forward_ref.py!} ``` _(This script is complete, it should run "as is")_ @@ -32,13 +32,13 @@ _(This script is complete, it should run "as is")_ For example, this works fine: ```py -{!./examples/postponed_works.py!} +{!.tmp_examples/postponed_works.py!} ``` While this will break: ```py -{!./examples/postponed_broken.py!} +{!.tmp_examples/postponed_broken.py!} ``` Resolving this is beyond the call for *pydantic*: either remove the future import or declare the types globally. @@ -52,7 +52,7 @@ with a friendly error message if you forget). Within the model, you can refer to the not-yet-constructed model using a string: ```py -{!./examples/self_referencing_string.py!} +{!.tmp_examples/self_referencing_string.py!} ``` _(This script is complete, it should run "as is")_ @@ -61,6 +61,6 @@ Since `python 3.7`, you can also refer it by its type, provided you import `anno and *pydantic* versions). ```py -{!./examples/self_referencing_annotations.py!} +{!.tmp_examples/self_referencing_annotations.py!} ``` _(This script is complete, it should run "as is")_ diff --git a/docs/usage/schema.md b/docs/usage/schema.md index 212f749..df75f7a 100644 --- a/docs/usage/schema.md +++ b/docs/usage/schema.md @@ -1,14 +1,14 @@ *Pydantic* allows auto creation of JSON Schemas from models: ```py -{!./examples/schema1.py!} +{!.tmp_examples/schema1.py!} ``` _(This script is complete, it should run "as is")_ Outputs: ```json -{!./examples/schema1.json!} +{!.tmp_examples/schema1.json!} ``` The generated schemas are compliant with the specifications: @@ -82,7 +82,7 @@ following priority order (when there is an equivalent available): The field schema mapping from Python / *pydantic* to JSON Schema is done as follows: -{!./.tmp_schema_mappings.html!} +{!.tmp_schema_mappings.html!} ## Top-level schema generation @@ -90,14 +90,14 @@ You can also generate a top-level JSON Schema that only includes a list of model sub-models in its `definitions`: ```py -{!./examples/schema2.py!} +{!.tmp_examples/schema2.py!} ``` _(This script is complete, it should run "as is")_ Outputs: ```json -{!./examples/schema2.json!} +{!.tmp_examples/schema2.json!} ``` ## Schema customization @@ -108,14 +108,14 @@ You can customize the generated `$ref` JSON location: the definitions are always This is useful if you need to extend or modify the JSON Schema default definitions location. E.g. with OpenAPI: ```py -{!./examples/schema3.py!} +{!.tmp_examples/schema3.py!} ``` _(This script is complete, it should run "as is")_ Outputs: ```json -{!./examples/schema3.json!} +{!.tmp_examples/schema3.json!} ``` It's also possible to extend/override the generated JSON schema in a model. @@ -125,12 +125,12 @@ To do it, use the `Config` sub-class attribute `schema_extra`. For example, you could add `examples` to the JSON Schema: ```py -{!./examples/schema4.py!} +{!.tmp_examples/schema4.py!} ``` _(This script is complete, it should run "as is")_ Outputs: ```json -{!./examples/schema4.json!} +{!.tmp_examples/schema4.json!} ``` diff --git a/docs/usage/settings.md b/docs/usage/settings.md index 0c588aa..52afea5 100644 --- a/docs/usage/settings.md +++ b/docs/usage/settings.md @@ -13,7 +13,7 @@ This makes it easy to: For example: ```py -{!./examples/settings.py!} +{!.tmp_examples/settings.py!} ``` _(This script is complete, it should run "as is")_ @@ -47,7 +47,7 @@ The following rules are used to determine which environment variable(s) are read Case-sensitivity can be turned on through the `Config`: ```py -{!./examples/settings_case_sensitive.py!} +{!.tmp_examples/settings_case_sensitive.py!} ``` When `case_sensitive` is `True`, the environment variable must be in all-caps, diff --git a/docs/usage/types.md b/docs/usage/types.md index 4f344ec..6ba7844 100644 --- a/docs/usage/types.md +++ b/docs/usage/types.md @@ -144,7 +144,7 @@ with custom properties and validation. *pydantic* uses standard library `typing` types as defined in PEP 484 to define complex objects. ```py -{!./examples/ex_typing.py!} +{!.tmp_examples/ex_typing.py!} ``` _(This script is complete, it should run "as is")_ @@ -156,7 +156,7 @@ The `Union` type allows a model attribute to accept different types, e.g.: This script is complete, it should run "as is". However, it may not reflect the desired behavior; see below. ```py -{!./examples/union_type_incorrect.py!} +{!.tmp_examples/union_type_incorrect.py!} ``` However, as can be seen above, *pydantic* will attempt to 'match' any of the types defined under `Union` and will use @@ -169,7 +169,7 @@ followed by less specific types. In the above example, the `UUID` class should p classes to preclude the unexpected representation as such: ```py -{!./examples/union_type_correct.py!} +{!.tmp_examples/union_type_correct.py!} ``` _(This script is complete, it should run "as is")_ @@ -178,7 +178,7 @@ _(This script is complete, it should run "as is")_ *pydantic* uses python's standard `enum` classes to define choices. ```py -{!./examples/choices.py!} +{!.tmp_examples/choices.py!} ``` _(This script is complete, it should run "as is")_ @@ -223,7 +223,7 @@ types: * `[±]P[DD]DT[HH]H[MM]M[SS]S` (ISO 8601 format for timedelta) ```py -{!./examples/datetime_example.py!} +{!.tmp_examples/datetime_example.py!} ``` ### Booleans @@ -249,7 +249,7 @@ A standard `bool` field will raise a `ValidationError` if the value is not one o Here is a script demonstrating some of these behaviors: ```py -{!./examples/boolean.py!} +{!.tmp_examples/boolean.py!} ``` _(This script is complete, it should run "as is")_ @@ -258,7 +258,7 @@ _(This script is complete, it should run "as is")_ Fields can also be of type `Callable`: ```py -{!./examples/callable.py!} +{!.tmp_examples/callable.py!} ``` _(This script is complete, it should run "as is")_ @@ -273,13 +273,13 @@ _(This script is complete, it should run "as is")_ that are subclasses of `T`. ```py -{!./examples/type_type.py!} +{!.tmp_examples/type_type.py!} ``` You may also use `Type` to specify that any class is allowed. ```py -{!./examples/bare_type_type.py!} +{!.tmp_examples/bare_type_type.py!} ``` ## Literal Type @@ -292,7 +292,7 @@ You may also use `Type` to specify that any class is allowed. may accept only specific literal values: ```py -{!./examples/literal1.py!} +{!.tmp_examples/literal1.py!} ``` _(This script is complete, it should run "as is")_ @@ -300,14 +300,14 @@ One benefit of this field type is that it can be used to check for equality with without needing to declare custom validators: ```py -{!./examples/literal2.py!} +{!.tmp_examples/literal2.py!} ``` _(This script is complete, it should run "as is")_ With proper ordering in an annotated `Union`, you can use this to parse types of decreasing specificity: ```py -{!./examples/literal3.py!} +{!.tmp_examples/literal3.py!} ``` _(This script is complete, it should run "as is")_ @@ -453,7 +453,7 @@ The above types (which all inherit from `AnyUrl`) will attempt to give descripti provided: ```py -{!./examples/urls.py!} +{!.tmp_examples/urls.py!} ``` _(This script is complete, it should run "as is")_ @@ -486,7 +486,7 @@ the above types export the following properties: If further validation is required, these properties can be used by validators to enforce specific behaviour: ```py -{!./examples/url_properties.py!} +{!.tmp_examples/url_properties.py!} ``` _(This script is complete, it should run "as is")_ @@ -497,7 +497,7 @@ _(This script is complete, it should run "as is")_ [this article](https://www.xudongz.com/blog/2017/idn-phishing/) for a good description of why this is important): ```py -{!./examples/url_punycode.py!} +{!.tmp_examples/url_punycode.py!} ``` _(This script is complete, it should run "as is")_ @@ -534,7 +534,7 @@ You can use the `Color` data type for storing colors as per (e.g. `"hsl(270, 60%, 70%)"`, `"hsl(270, 60%, 70%, .5)"`) ```py -{!./examples/ex_color_type.py!} +{!.tmp_examples/ex_color_type.py!} ``` _(This script is complete, it should run "as is")_ @@ -582,7 +582,7 @@ that you do not want to be visible in logging or tracebacks. The `SecretStr` and `SecretBytes` will be formatted as either `'**********'` or `''` on conversion to json. ```py -{!./examples/ex_secret_types.py!} +{!.tmp_examples/ex_secret_types.py!} ``` _(This script is complete, it should run "as is")_ @@ -593,7 +593,7 @@ It can also optionally be used to parse the loaded object into another type base the type `Json` is parameterised with: ```py -{!./examples/ex_json_type.py!} +{!.tmp_examples/ex_json_type.py!} ``` _(This script is complete, it should run "as is")_ @@ -603,7 +603,7 @@ The `PaymentCardNumber` type validates [payment cards](https://en.wikipedia.org/ (such as a debit or credit card). ```py -{!./examples/payment_card_number.py!} +{!.tmp_examples/payment_card_number.py!} ``` _(This script is complete, it should run "as is")_ @@ -626,7 +626,7 @@ The actual validation verifies the card number is: The value of numerous common types can be restricted using `con*` type functions: ```py -{!./examples/constrained_types.py!} +{!.tmp_examples/constrained_types.py!} ``` _(This script is complete, it should run "as is")_ @@ -645,7 +645,7 @@ The following caveats apply: - `StrictFloat` (and the `strict` option of `ConstrainedFloat`) will not accept `int`. ```py -{!./examples/strict_types.py!} +{!.tmp_examples/strict_types.py!} ``` _(This script is complete, it should run "as is")_ @@ -655,6 +655,6 @@ You can also define your own custom data types. The classmethod `__get_validator to get validators to parse and validate the input data. ```py -{!./examples/custom_data_types.py!} +{!.tmp_examples/custom_data_types.py!} ``` _(This script is complete, it should run "as is")_ diff --git a/docs/usage/validators.md b/docs/usage/validators.md index 320fea5..8284ac0 100644 --- a/docs/usage/validators.md +++ b/docs/usage/validators.md @@ -1,7 +1,7 @@ Custom validation and complex relationships between objects can be achieved using the `validator` decorator. ```py -{!./examples/validators_simple.py!} +{!.tmp_examples/validators_simple.py!} ``` _(This script is complete, it should run "as is")_ @@ -38,7 +38,7 @@ A few things to note on validators: Validators can do a few more complex things: ```py -{!./examples/validators_pre_item.py!} +{!.tmp_examples/validators_pre_item.py!} ``` _(This script is complete, it should run "as is")_ @@ -57,7 +57,7 @@ However there are situations where it may be useful or required to always call t to set a dynamic default value. ```py -{!./examples/validators_always.py!} +{!.tmp_examples/validators_always.py!} ``` _(This script is complete, it should run "as is")_ @@ -69,7 +69,7 @@ You'll often want to use this together with `pre`, since otherwise with `always= Validation can also be performed on the entire model's data. ```py -{!./examples/validators_root.py!} +{!.tmp_examples/validators_root.py!} ``` _(This script is complete, it should run "as is")_ @@ -93,6 +93,6 @@ In this case you should set `check_fields=False` on the validator. Validators also work with *pydantic* dataclasses. ```py -{!./examples/validators_dataclass.py!} +{!.tmp_examples/validators_dataclass.py!} ``` _(This script is complete, it should run "as is")_ diff --git a/runtime.txt b/runtime.txt index d70c8f8..475ba51 100644 --- a/runtime.txt +++ b/runtime.txt @@ -1 +1 @@ -3.6 +3.7